Reputation: 43
I am finding something like below. Constructing a where clause using condition. Is it possible in ruby? or I need to separate it into two where clause?
Post
.where(tag: "A") if condition A
.where(tag: "B") if condition B
.where(user_id: 1)
.order(....)
Actually, my case is like this. Is there any way to handle?
def this_function
@questions = Question.joins(:comment_threads)
.tagged_with(tag_variable, wild: true, any: true) if tag_variable.present?
.where(index_where_clause)
.where("questions.created_at < ?", query_from_date_time)
.order(created_at: :desc).limit(5)
end
def index_where_clause
where_clause = {}
where_clause[:user_detail_id] = current_user_detail.id if params[:type] == "my_question"
where_clause[:comments] = {user_detail_id: current_user_detail.id} if params[:type] == "my_answer"
where_clause[:wine_question_score_id] = params[:wine_question_score_id] if params[:wine_question_score_id].present?
where_clause
end
Upvotes: 1
Views: 529
Reputation: 4053
#in Question class
scope :with_user_detail, -> (user_detail_id, flag=true) do
where("user_detail_id = ?", user_detail_id) if flag
end
scope :with_user_detail_comments, -> (user_detail_id, flag=true) do
joins(:comment_threads).where("comments.user_detail_id = ?", user_detail_id) if flag
end
scope :with_wine_question_score, -> (wine_question_score_id) do
where("wine_question_score_id = ?", wine_question_score_id) if wine_question_score_id.present?
end
scope :tagged_with_condition, -> (tag_variable, wild, any) do
tagged_with(tag_variable, wild, any) if tag_variable.present?
end
def this_function
my_question_flag = params[:type] == "my_question"
my_answer_flag = params[:type] == "my_answer"
Question.with_user_detail(current_user_detail.id, my_question_flag)
.tagged_with_condition(tag_variable, wild: true, any: true)
.with_user_detail_comments(current_user_detail.id, my_answer_flag)
.with_wine_question_score(params[:wine_question_score_id])
.order(created_at: :desc).limit(5)
end
Upvotes: 1
Reputation: 479
#tap
can be helpful for modifying an object in place to apply conditional logic, in this case the object would be your .where
conditions:
Post
.where(
{ user_id: 1 }
.tap do |conditions|
conditions[:tag] = 'A' if condition A
conditions[:tag] = 'B' if condition B
end
)
.order(...)
Or, perhaps it's a little cleaner if you create a helper method:
def specific_conditions
{ user_id: 1 }.tap do |conditions|
conditions[:tag] = 'A' if condition A
conditions[:tag] = 'B' if condition B
end
end
Post.where(specific_conditions).order(...)
But as a side note, if there's a case where condition A
and condition B
can both be true, the second conditions[:tag] = ...
line will override the first. If there is not a case where both can be true, you might try to use some kind of collection to look up the proper value for tag.
CONDITION_TAGS = {
a: 'A'.freeze,
b: 'B'.freeze,
}.freeze
def specific_conditions
{ user_id: 1 }
.tap do |conditions|
conditions[:tag] = CONDITION_TAGS[condition_value] if condition_value
end
end
Post.where(specific_conditions).order(...)
Upvotes: 1
Reputation: 434585
The methods you're using return relations so you can say things like this:
@questions = Question.joins(:comment_threads)
@questions = @questions.where("questions.created_at < ?", query_from_date_time)
@questions = @questions.tagged_with(tag_variable, wild: true, any: true) if tag_variable.present?
@questions = @questions.where(:user_detail_id => current_user_detail.id) if params[:type] == "my_question"
@questions = @questions.where(:comments => { user_detail_id: current_user_detail.id}) if params[:type] == "my_answer"
@questions = @questions.where(:wine_question_score_id => params[:wine_question_score_id]) if params[:wine_question_score_id].present?
@questions = @questions.order(created_at: :desc).limit(5)
and build the query piece by piece depending on what you have in params
.
I'd probably break it down a little more:
def whatever
@questions = Question.joins(:comment_threads)
@questions = @questions.where("questions.created_at < ?", query_from_date_time)
@questions = with_tag(@questions, tag_variable)
#...
@questions = @questions.order(created_at: :desc).limit(5)
end
private
def with_tag(q, tag)
if tag.present?
q.tagged_with(tag, wild: true, any: true)
else
q
end
end
#...
and bury all the noisy bits in little methods to make things cleaner and easier to read. If you're doing this more than once then you could use scopes to hide the noise in the model class and re-use it as needed.
Upvotes: 2
Reputation: 3722
you have to use scope
:
scope :my_scope, -> (variable) { where(some: vatiable) if my_condition }
Upvotes: 0
Reputation: 5831
You can do the following:
condition = {:tag => "A"} if condition A
condition = {:tag => "B"} if condition B
Post
.where(condition)
.where(:user_id => 1)
.order(....)
Upvotes: 0