I have the following nested if statement hairball, I'm wondering if there is a more efficient way of writing this code (less lines of code that doesn't require so many conditionals)
Each of the methods are named_scopes within the model..
box = (params[:b] ? params[:b] : "inbox")
show = (params[:s] ? params[:s] : "all")
if box == "inbox"
if show == "all"
@messages = @current_user.received_messages.all
elsif show == "unread"
@messages = @current_user.received_messages.unread.all
elsif show == "read"
@messages = @current_user.received_messages.read.all
elsif show == "starred"
@messages = @current_user.received_messages.starred.all
else
@messages = []
end
elsif box = "sent"
@messages = @current_user.sent_messages.all
else
@messages = []
end
My thought was that I could use a 'call' type of method for box and show like
@current_user.开发者_Python百科received_messages.call(:box).call(:show).all
maybe..?
UGH, should have spent a bit more time playing around.. its just as i thought, I was just using the wrong method SOLUTION
@current_user.send(box).send(show)
You can use the scoped()
method in rails 2.3.8 to chain scopes:
main_method = case (params[:s]||"inbox")
when "inbox"
:received_messages
when "sent"
:sent_messages
end
# create a scope. Don't execute the scope yet.
scope = @current_user.send(main_method).scoped({}) if main_method
# now chain the scope if needed
scope = begin
if ["unread", "read", "starred"].include?(params[:s])
scope.send(params[:s])
elsif((params[:s] || "all") == "all")
scope
end
end if main_method == :received_messages
@messages = scope.nil? ? [] : scope.all
Reference:
Scoped method source in Rails 2.3.x
Rails casts on Anonymous scopes in 2.3.x
Your answer is very close but it fails to convert box
values.
box = params[:b] || 'inbox'
show = params[:s] || 'all'
box_scope = case box
when 'inbox' then 'received_messages'
when 'sent' then 'sent_messages'
end
show_scope = show # no convertion needed at this point, maybe in the future
# If box_scope is nil, don't query
@messages = box_scope.nil? ? [] : @current_user.send(box_scope).send(show_scope)
This assumes you do away with the .all
you were using in the original code for all options, which disappeared in your answer.
This is what I figured out, I'm not going to mark my own answer as correct unless everyone agrees this is the best - any other ideas?
if params[:b].present? && ["received_messages", "sent_messages"].include?(params[:b])
box = params[:b]
if params[:s].present? && ["all", "unread", "starred"].include?(params[:s])
show = params[:s]
else
show = "all"
end
@messages = @current_user.send(box).send(show)
else
@messages = []
end
精彩评论