Rails标量查询

时间:2010-04-28 20:48:45

标签: ruby-on-rails lambda user-defined-functions

我需要为当前用户(另一名员工)的“收藏夹”显示一个UI元素(例如星号或复选标记)。

Employee模型定义了以下关系以支持此:

  has_and_belongs_to_many :favorites, :class_name => "Employee", :join_table => "favorites",
    :association_foreign_key => "favorite_id", :foreign_key => "employee_id"

收藏夹有两个字段:employee_id,favorite_id。

如果我要编写SQL,以下查询将为我提供我想要的结果:

SELECT  id, account, 
    IF(
    (
    SELECT  favorite_id
    FROM    favorites
    WHERE   favorite_id=p.id
    AND employee_id = ?
    ) IS NULL, FALSE, TRUE) isFavorite
FROM        employees

哪里'?'将由会话[:user_id]替换。

如何在Rails中表示isFavorite标量查询?

另一种方法是使用这样的查询:

SELECT  id, account, IF(favorite_id IS NULL, FALSE, TRUE) isFavorite
FROM        employees e
LEFT OUTER JOIN favorites f ON e.id=f.favorite_id
    AND employee_id = ?

再次,'?'由会话[:user_id]值替换。

我在Rails中写了一些成功:

ee=Employee.find(:all, :joins=>"LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=1", :select=>"employees.*,favorites.favorite_id")

不幸的是,当我尝试用“?”替换“1”来使这个查询“动态”时,我会收到错误。

ee=Employee.find(:all, :joins=>["LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=?",1], :select=>"employees.*,favorites.favorite_id")

显然,我的语法错误,但可以:将表达式加入'动态'吗?这是Lambda表达式的情况吗?

我希望为此查询添加其他过滤器,并将其与will_paginate和acts_as_taggable_on一起使用,如果这会产生影响。

修改

尝试使:joins动态出错:

ActiveRecord::ConfigurationError: Association named 'LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=?' was not found; perhaps you misspelled it?
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1906:in `build'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1911:in `build'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1910:in `each'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1910:in `build'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1830:in `initialize'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1789:in `new'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1789:in `add_joins!'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1686:in `construct_finder_sql'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1548:in `find_every'
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:615:in `find'

3 个答案:

答案 0 :(得分:3)

试试这个:

ee=Employee.all( 
  :select=>"employees.*,favorites.favorite_id",
  :joins=>"LEFT OUTER JOIN favorites AS favorites 
           ON employees.id=favorites.favorite_id AND
              favorites.employee_id = #{session[:user_id]}")

或者确切地说:

joins = Employee.send(:sanitize_sql_array, 
             ["LEFT OUTER JOIN favorites AS favorites 
               ON employees.id=favorites.favorite_id AND
                  favorites.employee_id = ? ", session[:user_id]
             ])

ee=Employee.find(:all, 
  :select=>"employees.*,favorites.favorite_id",
  :joins=> joins )

第二种方法解决了SQL注入问题。

修改1

要在irb中测试这些来电,请执行以下操作:

通过创建哈希来模拟会话对象:

>> session = {:user_id => "1" }
session = {:user_id => "1" }
=> {:user_id=>"1"}

执行取景器:

>> ee=Employee.find(:all, 
      :select=>"employees.*,favorites.favorite_id",
      :joins=>"LEFT OUTER JOIN favorites AS favorites 
               ON employees.id=favorites.favorite_id AND
                  favorites.employee_id = #{session[:user_id]}")

答案 1 :(得分:0)

我想两种方式都是可能的,但通常情况下,我会在WHERE子句(:conditions)中坚持使用条件:

ee = Employee.find(:all,
    :select => 'employees.*, favorites.favorite_id',
    :conditions => ['favorites.employee_id = ?', 1],
    :joins => 'LEFT OUTER JOIN favorites ON employees.id = favorites.favorite_id'
)

答案 2 :(得分:0)

:joins需要原始字符串或符号(关联名称)或关联数组。所以你不能拥有动态条件。

请参阅参数部分here