Wszelkie uwagi a nawet wiadra pomyj mile widziane. Po kolei:
Mamy 2 klasy userów: normalny i admin.
Mamy model Bet, który dzieli się na 6+1 zdefiniowanych na podstawie różnych parametrów kategorii (statusów):
class Bet < ActiveRecord::Base
scope :visible, lambda { where('bets.published_at IS NOT NULL and bets.banned = ?', 0) }
scope :active, lambda { visible.where('bets.deadline > ? and bets.closed_at IS NULL', Time.now.strftime("%Y-%m-%d")) }
scope :waiting, lambda { visible.where('bets.deadline <= ? and bets.closed_at IS NULL', Time.now.strftime("%Y-%m-%d")) }
scope :closed, lambda { visible.where('bets.closed_at IS NOT NULL') }
scope :created, lambda { where('bets.published_at IS NULL and bets.closed_at IS NULL') }
scope :rejected, lambda { where('bets.published_at IS NULL and bets.closed_at IS NOT NULL') }
scope :banned, lambda { where('bets.banned = ?', 1) }
6+1 jest dlatego, że “visible” jest pomocniczo, żeby uprościć definicję 3 innych kategorii.
Definicje etykiet do wyświetlania wyglądają tak (nazwa scope’a => tekst etykiety/linka):
private
def Bet.status_names(admin)
statuses = {
'active' => 'aktywne',
'waiting' => 'oczekujące',
'closed' => 'zakończone',
}
if admin == true
return statuses.merge({
'created' => 'nowe',
'rejected' => 'odrzucone',
'banned' => 'usunięte'
})
end
statuses
end
def Bet.order_names
{ 'oldest' => 'najstarsze', 'newest' => 'najnowsze' }
end
(‘oldest’ i ‘newest’ to wiadomo - dodane sortowanie).
Kontroler pobiera te hashe żeby przekazać do widoku i wyświetlić oraz pobiera rekordy na podstawie parametrów.
def index
@bets = Bet.for_display(params)
@status_names = Bet.status_names(current_user.admin?)
@order_names = Bet.order_names
@categories = Category.all
@status = @status_names.keys.include?(params[:status]) ? @status_names[params[:status]] : 'widoczne'
end
Widok:
<div>Pokaż: <%= render partial: 'shared/querystring', locals: { key: 'status', object: @status_names } %></div>
i partial (wiem, lepsza nazwa by się przydała ;)):
<% object.each do |name, value| %>
<%= link_to value, "/bets/?#{query_string(params, key, name)}" %>
<% end %>
query_string() formatuje parametry, żeby zastąpić tylko odpowiedni z nich nową wartością.
I jest wszystko fajnie tylko że w metodzie wyszukującej rekordy również korzystam z Bet.status_names, żeby nie wywołać nieprawidłowego scope (btw. jaka nazwa obowiązuje po polsku na to?).
def Bet.for_display(params)
scope1 = status_names(true).keys.include?(params[:status]) ? Bet.send(params[:status]) : Bet.visible
if scope1 && !params[:order].nil?
scope2 = Bet.send(params[:order])
end
merged = scope1 ? scope1.merge(scope2) : nil
if merged && !params[:category].nil?
scope3 = Bet.where('category_id = ?', params[:category])
end
merged = merged ? merged.merge(scope3) : []
end
Oczywiście w takiej postaci będą wyświetlane 3 etykietki dla usera a 6 dla admina ale i tak można zobaczyć inne przez wpisanie np. ?status=banned w adresie.
Można to zabezpieczyć przez dołączenie parametru ‘admin’ dodatkowo:
def Bet.for_display(params, admin)
i w pierwszej linii status_names(admin) zamiast true.
No ale… nie pasuje mi coś w tym rozwiązaniu, dlatego chciałbym usłyszeć jakieś opinie, co tu jest źle i jak to można rozwiązać bardziej elegancko.
Myślałem np. żeby zamiast tych wszystkich warunków dać jedno pole pt “status” co by uprościło filtrowanie.