set*_*rgo 27 activerecord ruby-on-rails ruby-on-rails-3
我不明白如何从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 | |
+----------------+--------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)
> 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 | |
| . . . . . . |
| . . . . . . |
| . . . . . . |
+----------------+--------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)
在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 | ... |
+----+-----------+----------+---------------------+---------+---------------+-----+
Run Code Online (Sandbox Code Playgroud)
看看如何将两个表的所有列连接在一起?但是,当我在Rails中运行相同的查询时,我没有得到我想要的所有列 - 我只从Profile中获取这些列:
# 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
Run Code Online (Sandbox Code Playgroud)
我想(有效地)返回一个具有Profile和User的所有属性的对象.我不想:包含用户,因为它没有意义.用户应始终是最新配置文件的一部分,就好像它们是配置文件模型中的字段一样.我该如何做到这一点?
我认为这个问题与Profile模型没有User的属性这一事实有关...
Lex*_*sey 18
使用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 | |
+------------+--------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)
我将在views/rights/index.html.erb中使用TagName和TagColor,因此我希望权限控制器将这些列包含在它传递给视图的@rights对象中.由于不是每个:right都有:tag,我想使用外连接:
@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id")
Run Code Online (Sandbox Code Playgroud)
但是,正如每个人都发现的那样,仅此一项不起作用:对TagName的块引用会产生服务器错误.但是,如果我在最后添加一个选择,一切都很好:
@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id").select("rights.*,tags.TagName as TagName,tags.TagColor as TagColor")
Run Code Online (Sandbox Code Playgroud)
注意添加6/7/13:select子句不需要别名 - 这也适用:
.select("rights.*,tags.TagName,tags.TagColor")
Run Code Online (Sandbox Code Playgroud)
现在我可以在我的视图中引用TagName和TagColor:
<% @rights.each do |right| %>
<tr ALIGN=Left <%=
# color background if this is tagged
" BGCOLOR=#{right.TagColor}" if right.TagColor
%> > ...
<% end %>
Run Code Online (Sandbox Code Playgroud)
kle*_*lew 11
我不认为您可以通过加入Rails加载用户和配置文件.我认为在早期版本的Rails(<2.1)中,关联模型的加载是通过连接完成的,但效率不高.这里有一些解释和其他材料的链接.
因此,即使您明确表示要加入它,Rails也不会将其映射到关联模型.所以如果你说Profile.whatever_here
它将永远映射到Profile
对象.
如果你仍想做你所说的问题,那么你可以自己调用自定义sql查询并处理结果:
p = ActiveRecord::Base.connection.execute("SELECT * FROM profiles JOIN users ON profiles.user_id = users.id LIMIT 1")
Run Code Online (Sandbox Code Playgroud)
并逐行获得结果:
p.fetch_row
Run Code Online (Sandbox Code Playgroud)
它已经成为一个阵列.
你的错误是因为你在对象上调用first_name
和user
方法AciveRecord::Relation
,它存储一个Profile
对象数组,而不是一个对象.所以
p = Profile.joins(:user).limit(1)
p[0].first_name
Run Code Online (Sandbox Code Playgroud)
干了工作.
获取一条记录的更好方法是调用:
p = Profile.joins(:user).first
p.first_name
p.user
Run Code Online (Sandbox Code Playgroud)
但是当你调用p.user
它时会查询数据库.要避免它,您可以使用include
,但如果只加载一个配置文件对象,则它是无用的.如果您一次加载许多配置文件并希望包含用户表,则会有所不同.
小智 8
尝试使用 select("*").joins(:table)
在这种情况下,您将键入:
User.select("*").joins(:profile)
Run Code Online (Sandbox Code Playgroud)
希望这对你有用。
阅读这些技巧后,我通过阅读3 种在 Rails 3 & 4 中进行预先加载(预加载)的方法,将所有连接加载到一个查询中。
我正在使用 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)
Run Code Online (Sandbox Code Playgroud)
这是我的其他尝试。
#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 :)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
31347 次 |
最近记录: |