如何使用if在ruby中构造where子句

时间:2016-01-23 19:11:20

标签: ruby-on-rails ruby activerecord rails-activerecord

我发现下面的内容。使用条件构造where子句。红宝石有可能吗?或者我需要将它分成两个where子句?

Post
  .where(tag: "A") if condition A
  .where(tag: "B") if condition B
  .where(user_id: 1)
  .order(....)

实际上,我的情况是这样的。有办法处理吗?

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

5 个答案:

答案 0 :(得分:2)

你正在使用的方法返回关系,所以你可以这样说:

@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)

并根据params中的内容逐个构建查询。

我可能会把它分解一点:

  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

  #...

并以小方法掩埋所有噪音,使事物更清洁,更容易阅读。如果您不止一次这样做,那么您可以使用范围来隐藏模型类中的噪声并根据需要重新使用它。

答案 1 :(得分:1)

#tap可以帮助修改适当的对象以应用条件逻辑,在这种情况下,对象将是您的.where条件:

Post
.where(
  { user_id: 1 }
  .tap do |conditions|
    conditions[:tag] = 'A' if condition A
    conditions[:tag] = 'B' if condition B
  end
)
.order(...)

或者,如果你创建一个辅助方法,它可能会更清洁一些:

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(...)

但是作为旁注,如果condition Acondition B都可以为真,则第二条conditions[: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(...)

答案 2 :(得分:1)

#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

答案 3 :(得分:0)

您可以执行以下操作:

condition = {:tag => "A"} if condition A
condition = {:tag => "B"} if condition B

Post
   .where(condition)
   .where(:user_id => 1)
   .order(....)

答案 4 :(得分:0)

你必须使用scope

scope :my_scope, -> (variable) { where(some: vatiable) if my_condition }