在我的应用程序中,用户has_many票证.不幸的是,票证表没有user_id:它有一个user_login(它是一个遗留数据库).我有一天会改变这一点,但是现在这种改变会产生太多影响.
那么如何通过登录列构建"用户has_many:ticket"关联?
我尝试了以下finder_sql,但它不起作用.
class User < ActiveRecord::Base
has_many :tickets,
:finder_sql => 'select t.* from tickets t where t.user_login=#{login}'
...
end
Run Code Online (Sandbox Code Playgroud)
我得到一个奇怪的错误:
ArgumentError: /var/lib/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:402:in `to_constant_name': Anonymous modules have no name to be referenced by
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/base.rb:2355:in `interpolate_sql'
from /var/lib/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:214:in `qualified_name_for'
from /var/lib/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:477:in `const_missing'
from (eval):1:in `interpolate_sql'
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/association_proxy.rb:95:in `send'
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/association_proxy.rb:95:in `interpolate_sql'
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/has_many_association.rb:143:in `construct_sql'
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/has_many_association.rb:6:in `initialize'
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1032:in `new'
from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1032:in `tickets'
from (irb):1
Run Code Online (Sandbox Code Playgroud)
我也试过这个finder_sql(在登录时使用双引号):
:finder_sql => 'select t.* from tickets t where t.user_login="#{login}"'
Run Code Online (Sandbox Code Playgroud)
但它以同样的方式失败(无论如何,如果它工作,它将容易受到sql注入).
在测试数据库中,我在ticket表中添加了一个user_id列,并尝试了这个finder_sql:
:finder_sql …Run Code Online (Sandbox Code Playgroud) 我们正在构建一个应用程序来创建类似于Facebook的组页面的组页面.有人可以发布到页面,该帖子可以有回复.由于它们具有非常相似的属性,因此将帖子和回复组合到同一个STI表中
class Page < ActiveRecord::Base
has_many :posts
has_many :replies, through: :posts
end
class BasePost < ActiveRecord::Base
...
end
class Post < BasePost
belongs_to :page
...
end
class Reply < BasePost
belongs_to :post
...
end
Run Code Online (Sandbox Code Playgroud)
page.posts_and_replies为了找到页面的"最喜欢的帖子或回复"之类的内容,我们必须将帖子和回复结合起来,以便我们可以获得结果集,例如:
top_messages = page.posts_and_replies.order_by('total_likes DESC').limit(10)
Run Code Online (Sandbox Code Playgroud)
要posts_and_replies作为单个结果集进行排序,我们通常需要根据单个连接查询它们:
class Page < ActiveRecord::Base
has_many :posts
has_many :replies, through: :posts
has_many :posts_and_replies, class_name: 'BasePost'
end
# ideally we could then do queries such as
most_recent_messages = @page.posts_and_replies.order('created_at DESC').limit(10)
Run Code Online (Sandbox Code Playgroud)
我们不能这样做,因为page_id只存在posts.'回复'仅通过他们所属的帖子引用该页面.所以这次加入给了我们帖子而不是回复.
我正在将Rails应用程序移植到Rails 4.2.这个Rails应用程序在关联中包含一些相当复杂的手动SQL代码 - 部分是由于DB优化(例如子选择而不是JOIN),部分原因是由于在编写时没有可行的替代方案(Rails 3.0),部分原因是由于缺乏知识(我希望,至少 - 这很容易解决).
示例:InternalMessage类.可以在用户之间发送消息(InternalMessage的收件人和消息的"删除",存储在InternalMessagesRecipients中,因为可以有几个)并且可以读取,回复,转发和删除它们.该关联看起来像这样:
class User < AR::Base
has_many :internal_messages,
:finder_sql => "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " +
' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' +
' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}',
:counter_sql => 'SELECT count(DISTINCT(internal_messages.id)) FROM internal_messages ' +
' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' +
' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}'
# ...
end
Run Code Online (Sandbox Code Playgroud)
关键部分是最后的"OR"子句 - 通过这种关联,我希望获得接收和发送的消息,这些消息与用户表单独连接:
has_many :sent_messages, -> { where(:sender_deleted_at => nil) }, :class_name => 'InternalMessage', …Run Code Online (Sandbox Code Playgroud) 我有盒子和球.球在盒子里.球可以是红色和绿色.
class Box < ActiveRecord::Base
has_many :balls
end
class Ball < ActiveRecord::Base
belongs_to :box
scope :green, where(:color => "green")
end
Run Code Online (Sandbox Code Playgroud)
我想只用绿球设置has_many.我知道finder_sql方法存在,但我不知道如何通过范围设置.
我希望以下示例相同:
@orders = @box.balls
@orders = @box.balls.green
Run Code Online (Sandbox Code Playgroud) 我有一个问题,我使用的查询finder_sql在移交给PostgreSQL之前没有正确解析导致数据库语法错误.
为了说明问题,我刚才使用了示例代码:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
我只改为class_name,"User"因为我没有人模型,但这在这里无关紧要.
has_many :subscribers, :class_name => "User", :finder_sql =>
'SELECT DISTINCT people.* ' +
'FROM people p, post_subscriptions ps ' +
'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
'ORDER BY p.first_name'
Run Code Online (Sandbox Code Playgroud)
当我使用它时,我收到以下错误:
User Load (0.3ms) SELECT DISTINCT people.* FROM people p, post_subscriptions ps WHERE
ps.post_id = #{id} AND ps.person_id = p.id ORDER BY p.first_name
PGError: ERROR: Syntaxerror near »{«
LINE 1: ...ople p, post_subscriptions ps WHERE ps.post_id = #{id} …Run Code Online (Sandbox Code Playgroud) postgresql activerecord ruby-on-rails finder-sql ruby-on-rails-3
我需要执行此查询以找出MySQL将用于特定表的下一个auto_increment值.
find_by_sql ["select auto_increment from information_schema.tables where
table_schema = ? and table_name = ? and auto_increment is not null", db_name, tbl_name]
Run Code Online (Sandbox Code Playgroud)
如何调用此特定查询?这适用于我调用它的任何模型,返回包含模型对象的大小为1的数组.编辑:该对象包含一个名为attributes的哈希,它包含所需的auto_increment值.
有没有其他方法来运行这样的通用查询?想知道使用find_by_sql的整个方法的变化是否也可以解决原始问题.