Reputation: 2051
I have a dropdown in a form and based on what the user selects I need to perform different queries. What's the best way to accomplish this? Could I have 2 functions where I get the privacy_level and then process what query to use in order to pass that value to the 2nd function?
def get_article_restrictions(privacy_level)
case privacy_level
when 0
"#{@authenticated_user.id} = articles.user_id"
when 1
"query 1"
when 2
"query 2"
end
end
in the 2nd function I would use whatever query was returned from the 1st function.
def display_articles
privacy_level = get_article_restrictions(params[:privacy_level])
@articles = Article.includes(:user).where(privacy_level)
end
Upvotes: 0
Views: 666
Reputation: 21110
mrzasa suggested in his answer to move the method to a model. Here is an example of how this could look.
class Article < ApplicationRecord
# ...
def self.privacy_level(level, user)
case level
when 0
where(user_id: user.id)
when 1
where(attribute: 'value')
when 2
where(attribute: 'value')
else
# Return the current scope without adding constraints.
where(nil)
end
end
# ...
end
Then in the controller simply call the scope.
def display_articles
@articles = Article.includes(:user)
.privacy_level(params[:privacy_level], @authenticated_user)
end
Keep in mind that most request parameters arive as strings, meaning only the else case is going to match. You can resolve this by changing the cases to when 0, '0'
instead of when 0
.
You might also want to move the default case into the else statement. This way when no level is given (params[:privacy_level]
equals nil
) you still constrain the fetched records.
Upvotes: 0
Reputation: 23307
It depends on the query you need to perform. If it's just a simple where
, you can pass a hash with where
params:
def get_article_restrictions(privacy_level)
case privacy_level
when 0
{ "articles.user_id": @authenticated_user.id }
when 1
{ param1: value1, param2: value2 }
when 2
{ param3: value3, param4: value4 }
end
end
def display_articles
privacy_level = get_article_restrictions(params[:privacy_level])
@articles = Article.includes(:user).where(privacy_level)
end
I would suggest doing it the other way around: pass the scope to the method:
def fetch_articles(scope, privacy_level)
case privacy_level
when 0
scope.where("articles.user_id": @authenticated_user.id)
when 1
scope.where(param1: value1, param2: value2)
when 2
scope.where(param3: value3, param4: value4)
end
end
def display_articles
@articles = fetch_articles(Article.includes(:user), params[:privacy_level])
end
I'd also suggest to move fetch_articles
to the modes, as calling active record methods (like where
) causes too much coupling and makes testing harder.
Upvotes: 2