Ruby on rails Rails从联接表联接和包含列

Ruby on rails Rails从联接表联接和包含列,ruby-on-rails,activerecord,ruby-on-rails-3,Ruby On Rails,Activerecord,Ruby On Rails 3,我不知道如何从rails获取我想要的列。我有两个模型-一个用户和一个配置文件。用户:拥有多个配置文件(因为用户可以恢复到其配置文件的早期版本): 在SQL中,我可以运行以下查询: > SELECT * FROM profiles JOIN users ON profiles.user_id = users.id LIMIT 1; +----+-----------+----------+---------------------+---------+---------------+---

我不知道如何从rails获取我想要的列。我有两个模型-一个用户和一个配置文件。用户:拥有多个配置文件(因为用户可以恢复到其配置文件的早期版本):

在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          | ... |
+----+-----------+----------+---------------------+---------+---------------+-----+
查看如何将两个表的所有列连接在一起?然而,当我在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
rails控制台中的
#
>>p=Profile.joins(:user).limit(1)
>> [#]
>>p.名字
>>NoMethodError:from/Library/Ruby/Gems/1.8/Gems/activerecord-3.0.1/lib/active\u record/relation的未定义方法“first\u name”。rb:373:in'method\u missing'from(irb):8
#我不想这样做(即我不想使用“包含”)
>>p.user
>>NoMethodError:from/Library/Ruby/Gems/1.8/Gems/activerecord-3.0.1/lib/active\u record/relation的未定义方法“user”。rb:373:in-method\u-missing”from(irb):9
我希望(高效地)返回一个对象,该对象同时具有Profile和User的所有属性。我不想:包括用户,因为它没有意义。用户应该始终是最新配置文件的一部分,就像它们是配置文件模型中的字段一样。我如何做到这一点


我认为问题与配置文件模型没有用户属性这一事实有关…

我不认为可以使用join-in Rails加载用户和配置文件。我认为在早期版本的Rails(<2.1)中,关联模型的加载是通过连接完成的,但效率不高。你有一些解释和其他材料的链接

因此,即使您明确表示希望加入它,Rails也不会将其映射到相关模型。所以,如果你说
Profile。不管这里有什么
,它都会被映射到
Profile
对象

如果您仍然想执行您所说的,那么您可以自己调用自定义sql查询并处理结果:

p = ActiveRecord::Base.connection.execute("SELECT * FROM profiles JOIN users ON profiles.user_id = users.id LIMIT 1")
并使用以下命令逐行获取结果:

p.fetch_row
它将已经映射到一个数组

您的错误是因为您正在调用
AciveRecord::Relation
对象上的
first\u name
user
方法,并且它存储了
Profile
对象的数组,而不是单个对象。所以

p = Profile.joins(:user).limit(1)
p[0].first_name
应该工作

仅获取一条记录的更好方法是调用:

p = Profile.joins(:user).first
p.first_name
p.user
但当您调用
p.user
时,它将查询数据库。为了避免这种情况,您可以使用
include
,但如果您只加载一个概要文件对象,则它是无用的。如果您一次加载多个配置文件,并希望在用户表中输入内容,则情况会有所不同。

使用select()来命名所需的列。至少在Rails 3.0.9中是这样

背景:我的应用程序有一个名为:rights的主表。我希望能够将标签和颜色归因于给定的:正确的记录,这样我就可以轻松地从索引列表中选择它。这与相关记录的Rails图片不完全匹配;most:永远不会标记权限,并且标记完全是任意的(用户通过标记/编辑输入)

我可以尝试复制: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控制器在传递给视图的@rights对象中包含这些列。因为不是每个:right都有:标记,所以我想使用外部联接:

@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id")
但是,正如每个人都发现的那样,单凭这一点是行不通的:对标记名的块引用会产生一个服务器错误。但是,如果在末尾添加一个select,则一切正常:

@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id").select("rights.*,tags.TagName as TagName,tags.TagColor as TagColor")
注:2013年6月7日添加:select子句不需要别名-这也适用于:

.select("rights.*,tags.TagName,tags.TagColor")
现在我可以在视图中引用标记名和标记颜色:

<% @rights.each do |right| %>
  <tr ALIGN=Left <%=
  # color background if this is tagged
  " BGCOLOR=#{right.TagColor}" if right.TagColor
  %> > ...
<% end %>

...

我已经解决了这个问题,在数据库中创建了一个视图作为连接,然后在代码中引用它,就好像它是一个普通的ActiveRecord表一样。这对于从数据库中获取数据是很好的,但是如果需要更新它,则需要返回表示“真实”表的基类。我发现这种方法在编写使用大型表格的报告时非常方便——你可以一次就把数据全部拿出来。我很惊讶,这似乎并没有内置到ActiveRecord中,对我来说似乎是一件显而易见的事情

所以对你来说:

在SQL中:

CREATE VIEW User_Profiles
AS
SELECT P.*, U.first_name
FROM Users U
inner join Profiles P on U.id=P.user_id
在RUBY模型文件中:

class UserProfile < ActiveRecord::Base
  self.primary_key = :id 
  #same dependencies as profiles
end
class-UserProfile
**提示。。。我总是忘记设置视图的所有者(我使用postgres),因此它会立刻爆发出许多咒骂和自责

尝试使用
选择(“*”)。联接(:表)

在这种情况下,您可以键入:

User.select("*").joins(:profile)

希望这对你有用。

在阅读了这些技巧之后,我通过阅读将所有连接加载到一个查询中

我正在使用Rails 4,这对我来说很有吸引力:

refs = Referral.joins(:job)
          .joins(:referee)
          .joins(:referrer)
          .where("jobs.poster_id= ?", user.contact_id)
          .order(created_at: :desc) 
          .eager_load(:job, :referee, :referrer)
这是我的其他尝试

#first attempt
#refs = Referral.joins(:job)
#          .where("jobs.poster_id= ?", user.contact_id)
#          .select("referrals.*, jobs.*")
# works, but each column needs to be explicitly referenced to be used later.
# also there are conflicts for columns with the same name like id

#second attempt
#refs = ActiveRecord::Base.connection.exec_query("SELECT jobs.id AS job_id, jobs.*, referrals.id as referral_id, referrals.* FROM referrals INNER JOIN jobs ON job_id = referrals.job_id WHERE (jobs.poster_id=#{user.contact_id});")
# this worked OK, but returned back a funky object, plus the column name
# conflict from the previous method remains an issue.


#third attempt using a view + rails_db_views
#refs = JobReferral.where(:poster_id => user.contact_id)
# this worked well. Unfortunately I couldn't use the SQL statement from above
# instead of jobs.* I had to explicitly alias and name each column.
# Additionally it brought back a ton of duplicate data that I was putting
# into an array when really it is nice to work with ActiveRecord objects.

#eager_load
#refs = Referral.joins(:job)
#          .where("jobs.poster_id= ?", user.contact_id)
#          .eager_load(:job)
# this was my base attempt that worked before I added in two more joins :)

为什么要在概要文件模型中包含用户字段?很明显,您有两个独立的模型,profile和user。通过使用include,您可以在一个查询中获取两个实体的数据,然后只执行profile.users,因为它不是一个查询…:include生成两个查询请注意,在控制台中键入
@rights
将不会显示额外的标记元素。但是键入
@rights.TagName
将显示这些值;在需要特定列值之前,不会实际读取数据库。您知道在这种情况下,是否有任何方法可以使用
includes
而不是
joins
?我想做同样的事情,但是用
而不是
连接,我不确定这是否完全回答了问题。只有左表的数据被打印到
refs = Referral.joins(:job)
          .joins(:referee)
          .joins(:referrer)
          .where("jobs.poster_id= ?", user.contact_id)
          .order(created_at: :desc) 
          .eager_load(:job, :referee, :referrer)
#first attempt
#refs = Referral.joins(:job)
#          .where("jobs.poster_id= ?", user.contact_id)
#          .select("referrals.*, jobs.*")
# works, but each column needs to be explicitly referenced to be used later.
# also there are conflicts for columns with the same name like id

#second attempt
#refs = ActiveRecord::Base.connection.exec_query("SELECT jobs.id AS job_id, jobs.*, referrals.id as referral_id, referrals.* FROM referrals INNER JOIN jobs ON job_id = referrals.job_id WHERE (jobs.poster_id=#{user.contact_id});")
# this worked OK, but returned back a funky object, plus the column name
# conflict from the previous method remains an issue.


#third attempt using a view + rails_db_views
#refs = JobReferral.where(:poster_id => user.contact_id)
# this worked well. Unfortunately I couldn't use the SQL statement from above
# instead of jobs.* I had to explicitly alias and name each column.
# Additionally it brought back a ton of duplicate data that I was putting
# into an array when really it is nice to work with ActiveRecord objects.

#eager_load
#refs = Referral.joins(:job)
#          .where("jobs.poster_id= ?", user.contact_id)
#          .eager_load(:job)
# this was my base attempt that worked before I added in two more joins :)