Rails 标量查询

发布于 2024-08-30 20:36:48 字数 2945 浏览 2 评论 0原文

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

Employee 模型定义了以下关系来支持这一点:

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

favorites 有两个字段: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 = ?

同样,“?”被 session[: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")

显然,我的语法错误,但是 :joins 表达式可以是“动态的”吗?这是 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'

I need to display a UI element (e.g. a star or checkmark) for employees that are 'favorites' of the current user (another employee).

The Employee model has the following relationship defined to support this:

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

The favorites has two fields: employee_id, favorite_id.

If I were to write SQL, the following query would give me the results that I want:

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

Where the '?' would be replaced by the session[:user_id].

How do I represent the isFavorite scalar query in Rails?

Another approach would use a query like this:

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 = ?

Again, the '?' is replaced by the session[:user_id] value.

I've had some success writing this in 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")

Unfortunately, when I try to make this query 'dynamic' by replacing the '1' with a '?', I get errors.

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

Obviously, I have the syntax wrong, but can :joins expressions be 'dynamic'? Is this a case for a Lambda expression?

I do hope to add other filters to this query and use it with will_paginate and acts_as_taggable_on, if that makes a difference.

edit

errors from trying to make :joins dynamic:

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'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葵雨 2024-09-06 20:36:48

试试这个:

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]}")

Try this:

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]}")

Or to be exact:

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 )

Second approach addresses the SQL injection issues.

Edit 1

To test these calls in irb do the following:

Simulate the session object by creating hash:

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

Execute the finder:

>> 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]}")
我不是你的备胎 2024-09-06 20:36:48

我想这两种方式都是可能的,但通常情况下,我会将条件放在 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'
)

I imagine both ways are possible, but normally, I'd stick the condition in the WHERE clause (: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'
)
小女人ら 2024-09-06 20:36:48

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

请参阅此处的参数部分。

:joins expects either a raw string or a symbol (association name), or an array of associations. So you can't have dynamic conditions there.

See parameters section here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文