使用字符串或实例变量时,ActiveRecord查询会有所不同

时间:2017-05-14 05:33:20

标签: ruby activerecord

如果您查看查询,@bot_client_id是一个具有相同值string的字符串。但是,当我将它们作为查询的一部分使用时,我会得到不同的结果。

为什么?

[24] pry(#<BotResponse>):1> string
=> "aiaas-1409611358153-user-0149"

[25] pry(#<BotResponse>):1> @bot_client_id
=> "aiaas-1409611358153-user-0149"

[26] pry(#<BotResponse>):1> Event.where.has{(status == 'active') & (bot_client_id == @bot_client_id)}
=> []
[27] pry(#<BotResponse>):1> Event.where.has{(status == 'active') & (bot_client_id == string)}
=> [#<Event:0x0000000464d120
  id: 22,
  bot_client_id: "aiaas-1409611358153-user-0149",
  keyword: "gratitude",
  topic: nil,
  status: "active",
  channel: "telegram",
  created_date: 2017-05-09 15:56:51 UTC,
  tickle_expression: "daily",
  time_of_day: "7:00 am",
  next_occurrence: 2017-05-14 14:00:00 UTC,
  time_zone: "America/Los_Angeles",
  recurring: true>,
 #<Event:0x0000000464cfb8
  id: 23,
  bot_client_id: "aiaas-1409611358153-user-0149",
  keyword: "daily_check",
  topic: nil,
  status: "active",
  channel: "telegram",
  created_date: 2017-05-10 04:25:47 UTC,
  tickle_expression: "daily",
  time_of_day: "9:00 am",
  next_occurrence: 2017-05-14 16:00:00 UTC,
  time_zone: "America/Los_Angeles",
  recurring: false>]

2 个答案:

答案 0 :(得分:2)

查看您的代码:

Event.where.has{(status == 'active') & (bot_client_id == @bot_client_id)}

has占用了statusbot_client_id被调用的区块。这两种方法似乎不太可能在外部环境中定义。

让我们看看当我们尝试使用未定义的变量调用块时会发生什么:

>> def method_calling_block
|    yield
|  end #=> :method_calling_block

>> method_calling_block { abcd }
NameError: undefined local variable or method `abcd' for main:Object
    from (irb):44:in `block in irb_binding'
    from (irb):40:in `method_calling_block'
    from (irb):44
    from /Users/fylooi/.rvm/rubies/ruby-2.1.4/bin/irb:11:in `<main>'

如果我们不打电话给该区块:

>> def method_without_calling_block
|  end #=> :method_without_calling_block

>> method_without_calling_block { abcd }  #=> nil

看起来传递到块中的变量仅在处理块时进行评估(通常使用yieldblock.call)。看起来这个块没有按正常方式处理。

一些谷歌搜索显示.where.has{}是属于的方法 BabySqueel。 BabySqueel文档指出:

  

BabySqueel的块使用instance_eval,这意味着您无法访问实例变量或方法。

https://github.com/rzane/baby_squeel/blob/master/lib/baby_squeel/dsl.rb

中的相关方法似乎为evaluate
module BabySqueel
  class DSL < Relation
    def evaluate(&block)
      if block.arity.zero?
        instance_eval(&block)
      else
        yield(self)
      end
    end 
  end
end

这意味着在

的上下文中
Event.where.has{(status == 'active') & (bot_client_id == @bot_client_id)}

@bot_client_id在接收者的绑定(这是BabySqueel::DSL个对象)中进行评估,而不是在调用者的绑定中进行评估。当然,它返回nil

要强制以常规方式评估块(即使用绑定到调用者的变量),您需要通过向其传递参数使block.arity.zero?求值为false

Event.where.has{|event| (event.status == 'active') & (event.bot_client_id == @bot_client_id)}

答案 1 :(得分:0)

据我所知,has {}方法是一个闭包,它改变了红宝石self范围。你可以通过以下命令看到它:

p self
Event.where.has{ p self; (status == 'active') & (bot_client_id == @bot_client_id) }

如果输出不同,则表示第二次执行中的@bot_client_id返回nil。