Scopes i linki to nich

Próbuję zastosować ten przykład: http://stackoverflow.com/questions/3665325/can-i-attach-a-named-scope-to-a-link-in-rails
Ale coś mi nie idzie:

[code=ruby]#kontroler
def index
# @ads = Ad.where(“advertiser_id IS NOT NULL AND verification_date IS NOT NULL”)
@ads = Ad.send(params[:scope] : ‘unverified_ads’)
end
#widok

  • link_to “Ogłoszenia niepotwierdzone”, verification_path(:scope => “unconfirmed_ads”)
    #model
    scope :unconfirmed_ads, :conditions => [“advertiser_id IS NULL”]
    scope :unverified_ads, :conditions => [“advertiser_id IS NOT NULL AND verification_date IS NOT NULL”][/code]
    ale dostaję błąd:
    syntax error, unexpected ‘:’, expecting ‘)’
    @ads = Ad.send(params[:scope] : ‘unverified_ads’)

Rozumiem, że powinienem dodać jakieś routes albo akcje do kontrolera?

params[:scope] : cos_innego

nie jest poprawną konstrukcją języka Ruby. Prawdopodobnie chodzi o Ad.send(params[:scope], costam_jako_parametr).

Tak czy inaczej: nie rób tego. Nie chcesz aby użytkownik mógł wysłać dowolną wiadomość do obiektu kasy. Pomyśl o tym co się stanie jeśli w params[:scope] będzie “delete_all”.

W takim razie jak dodalibyście linki do poszczególnych zakresów? Szukam dobrego rozwiązania bo problem wydaje mi się ciekawy.

Chodzi mi właśnie aby w panelu admina można było wyświetlać potwierdzone ogłoszenia, niepotwierdzone, wszystkie, tylko ogłoszenia danego użytkownika.

Szukam tego w sieci i znajduję tylko informacje o tym jak dodawać scopes.

Edit: może coś takiego jest dobrym rozwiązaniem: https://github.com/plataformatec/has_scope

Jeśli jest to panel administracyjny, ja bym przymknął oko na Model.send(params[:scope])

@ads = Ad.send(params[:scope])

Przy takim ustawieniu dostaję błąd: nil is not a symbol

I chciałbym aby defaultowo ustawić któryś zakres.

Nie no bez jaj - nawet w panelu admina przekazywanie czegoś bez walidacji do send to dla mnie porażka.
Zrób metodę, która akceptuje to samo, ale pozwala na wywołanie tylko zdefiniowanych scopów ogranicza, np.

[code=ruby]Ad.with_some_scope(params[:scope],…)

i definicja w klasie Ad

SCOPES = [“unconfirmed_ads”,“unverified_ads”]
def with_some_scope(scope_name,…)
raise “Invalid scope #{scope_name}” unless SCOPES.include?(scope_name)
end[/code]
Oczywiście to tylko szkic - w realnej implementacji lepiej byłoby się pozbyć stałej SCOPES.

[quote=regedarek]@ads = Ad.send(params[:scope])
Przy takim ustawieniu dostaję błąd: nil is not a symbol

I chciałbym aby defaultowo ustawić któryś zakres.[/quote]
To tym bardziej jest sens dodać metodę “with_some_scope” (czy jak ją tam sobie nazwiesz).

Nie lepiej takie sprawdzenie dać w constraints w routes-ach?

Jeżeli ktoś wpisze na produkcji jakiś dziwny url zamiast 500 dostanie 404 (które jakoś bardziej mi tu pasuje)

Znalazłem chyba jakieś rozwiązanie ale dla railsów 2 :slight_smile: Spróbuję to ogarnąć.
http://iain.nl/filtering-with-named-scopes

[quote=zlw]Nie lepiej takie sprawdzenie dać w constraints w routes-ach?

Jeżeli ktoś wpisze na produkcji jakiś dziwny url zamiast 500 dostanie 404 (które jakoś bardziej mi tu pasuje)[/quote]
Ostrożności nigdy za wiele - oczywiście dodanie constrainta w routach też jest na miejscu, ale wywoływanie metody na podstawie params, to proszenie się o kłopoty.

Co do błędu 500 - oczywiście w kontrolerze lub gdzieś indziej można dodać rescue - to jest tylko szkic rozwiązania.

W tej sytuacji case nada się najlepiej.

def index @ads = case params[:scope] when 'unverified_ads' Ad.unverified_ads when 'unconfirmed_ads' Ad.unconfirmed_ads else #domyslny scope Ad.unverified_ads end end
A params[:scope] to taki sam parametr jak np. params[:page].

No co do tego to jest zgoda - mój sprzeciw budzie jedynie wywołanie send(params[:cokolwiek]).

Dzięki przykład z case działa wyśmienicie :wink:

do routes dodałem tylko:

  match "/verifications/:scope" => "verifications#index"

A może tą część z case przesunąć do modelu?

Dobrze kombinujesz - fat model, thin controller.

Jak chcesz być hiper ostrożny to sprawdź scope też w routes-ach :wink:

[code=ruby]class Verification < ActiveRecord::Base
AVAILABLE_SCOPES = [:foo, :bar, :foobar]

def self.scoped_with(scope_name)
raise “Ooops!” unless AVAILABLE_SCOPES.include? scope_name
send(scope_name)
end
end

routes.rb

get “/verifications/:scope” => “verifications#index”, :constraints => { :scope => /#{Verification::AVAILABLE_SCOPES.join(’|’)}/ }[/code]

Cześć,
Chcę aby po kliknięciu w Fast Verification, a następnie Verify aby redirect_to było do verify_info_verification_path(Ad.unverified_ads.last, :fast => true)
Coś źle kombinuję strasznie.

[code=ruby]#verifications/index.haml
= link_to “Fast Verification”, verify_info_verification_path(Ad.unverified_ads.last, :fast => true)
= link_to “Normal Verify”, verify_info_verification_path(ad), :method => :put

#verifications/verify_info.haml
= link_to “Verify”, verify_verification_path(@ad)
#verification_controller.rb
def verify_info
@ad = Ad.find(params[:id])
end

def verify
@ad = Ad.find(params[:id])
@ad.update_attribute :verification_date, Time.now
if params[:fast] == true
redirect_to Ad.unverified_ads.last
else
redirect_to verifications_path
end
end[/code]