我不明白如何从rails获取我想要的列。我有两个模型 - 用户和个人资料。用户:has_many配置文件(因为用户可以恢复到其配置文件的早期版本):
> DESCRIBE users;
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(255) | NO | UNI | NULL | |
| password | varchar(255) | NO | | NULL | |
| last_login | datetime | YES | | NULL | |
+----------------+--------------+------+-----+---------+----------------+
> DESCRIBE profiles;
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| first_name | varchar(255) | NO | | NULL | |
| last_name | varchar(255) | NO | | NULL | |
| . . . . . . |
| . . . . . . |
| . . . . . . |
+----------------+--------------+------+-----+---------+----------------+
在SQL中,我可以运行查询:
> SELECT * FROM profiles JOIN users ON profiles.user_id = users.id LIMIT 1;
+----+-----------+----------+---------------------+---------+---------------+-----+
| id | username | password | last_login | user_id | first_name | ... |
+----+-----------+----------+---------------------+---------+---------------+-----+
| 1 | john | ****** | 2010-12-30 18:04:28 | 1 | John | ... |
+----+-----------+----------+---------------------+---------+---------------+-----+
看看如何将BOTH表的所有列连接在一起?但是,当我在Rails中运行相同的查询时,我没有得到我想要的所有列 - 我只从配置文件中获取这些:
# in rails console
>> p = Profile.joins(:user).limit(1)
>> [#<Profile ...>]
>> p.first_name
>> NoMethodError: undefined method `first_name' for #<ActiveRecord::Relation:0x102b521d0> from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.1/lib/active_record/relation.rb:373:in `method_missing' from (irb):8
# I do NOT want to do this (AKA I do NOT want to use "includes")
>> p.user
>> NoMethodError: undefined method `user' for #<ActiveRecord::Relation:0x102b521d0> from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.1/lib/active_record/relation.rb:373:in method_missing' from (irb):9
我想(有效地)返回一个具有Profile和User的所有属性的对象。我不想:包含用户,因为它没有意义。用户应始终是最新配置文件的一部分,就好像它们是配置文件模型中的字段一样。我该如何做到这一点?
我认为这个问题与Profile模型没有User ...
的属性这一事实有关答案 0 :(得分:17)
使用select()命名所需的列。至少这在Rails 3.0.9中有效。
后台:我的应用程序有一个名为:rights的主表。我希望能够将标签和颜色归因于给定的:正确的记录,以便我可以轻松地从索引列表中选择它。这并不完全符合相关记录的Rails图片;大多数:权限永远不会被标记,标签完全是任意的(用户通过标签/编辑输入)。
我可以尝试复制:right记录中的标记数据,但这违反了正常形式。或者我可以尝试查询:每个标签:正确的记录,但这是一种非常低效的方法。我希望能够加入这些表格。
MySQL控制台显示:
mysql> describe rights;
+------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
...
| Tagid | int(11) | YES | | NULL | |
+------------+---------------+------+-----+---------+----------------+
mysql> describe tags;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| TagName | varchar(255) | YES | | NULL | |
| TagColor | varchar(255) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
我将在views / rights / index.html.erb中使用TagName和TagColor,因此我希望权限控制器将这些列包含在它传递给视图的@rights对象中。由于不是每个:right都有:tag,我想使用外连接:
@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id")
但是,正如每个人都发现的那样,仅此一项不起作用:对TagName的块引用会产生服务器错误。但是,如果我在最后添加一个选择,一切都很好:
@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id").select("rights.*,tags.TagName as TagName,tags.TagColor as TagColor")
注意添加了6/7/13:select子句不需要别名 - 这也适用:
.select("rights.*,tags.TagName,tags.TagColor")
现在我可以在我的视图中引用TagName和TagColor:
<% @rights.each do |right| %>
<tr ALIGN=Left <%=
# color background if this is tagged
" BGCOLOR=#{right.TagColor}" if right.TagColor
%> > ...
<% end %>
答案 1 :(得分:10)
我认为您不能通过加入Rails加载用户和配置文件。我认为在早期版本的Rails(&lt; 2.1)中,相关模型的加载是通过连接完成的,但效率不高。 Here您有一些解释和其他材料的链接。
因此,即使您明确表示要加入它,Rails也不会将其映射到关联模型。因此,如果您说Profile.whatever_here
,它将始终映射到Profile
对象。
如果你仍想做你所说的话,你可以自己调用自定义sql查询并处理结果:
p = ActiveRecord::Base.connection.execute("SELECT * FROM profiles JOIN users ON profiles.user_id = users.id LIMIT 1")
并逐行获得结果:
p.fetch_row
它已经成为一个数组。
您的错误是因为您在first_name
对象上调用user
和AciveRecord::Relation
方法,并且它存储了Profile
个对象的数组,而不是单个对象。所以
p = Profile.joins(:user).limit(1)
p[0].first_name
工作。
只获取一条记录的更好方法是调用:
p = Profile.joins(:user).first
p.first_name
p.user
但是当你打电话给p.user
时,它会查询数据库。要避免它,您可以使用include
,但如果只加载一个配置文件对象,则它是无用的。如果您一次加载多个配置文件并希望包含用户表,则会有所不同。
答案 2 :(得分:4)
尝试使用select("*").joins(:table)
在这种情况下,您可以输入:
User.select("*").joins(:profile)
希望对你有用。
答案 3 :(得分:3)
阅读完这些提示后,通过阅读3 ways to do eager loading (preloading) in Rails 3 & 4,我将所有联接加载到一个查询中。
我正在使用Rails 4,这对我来说就像一个魅力:
kCLLocationAccuracyBest
这是我的其他尝试。
refs = Referral.joins(:job)
.joins(:referee)
.joins(:referrer)
.where("jobs.poster_id= ?", user.contact_id)
.order(created_at: :desc)
.eager_load(:job, :referee, :referrer)
答案 4 :(得分:2)
我通过在数据库中创建一个VIEW来解决这个问题,该数据库是连接,然后引用它就好像它是代码中的普通ActiveRecord表一样。这对于从数据库中获取数据很好,但如果您需要更新数据,那么您需要返回代表“真实”数据库的基类。表。我发现这种方法在使用biggish表的报表时很方便 - 你可以在一次点击中获取数据。我很惊讶这似乎没有内置到ActiveRecord中,对我来说似乎是显而易见的事情!
所以对你:
IN SQL:
CREATE VIEW User_Profiles
AS
SELECT P.*, U.first_name
FROM Users U
inner join Profiles P on U.id=P.user_id
IN RUBY模型文件:
class UserProfile < ActiveRecord::Base
self.primary_key = :id
#same dependencies as profiles
end
**提示......我总是忘记设置视图的所有者(我使用postgres),所以它会随着诅咒和自我反复而直接爆发。