2010-12-30 23 views
24

Raylardan istediğiniz sütunları nasıl elde edeceğimi anlamıyorum. İki modelim var - Bir Kullanıcı ve Bir Profil. Bir kullanıcı: (Kullanıcıların profil önceki bir sürümüne geri dönebilirsiniz çünkü) Has_many Profili:Raylar Katılır ve birleşimler tablosundan sütunlar ekleyin

> 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   | ... | 
+----+-----------+----------+---------------------+---------+---------------+-----+ 
:

> 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, ben sorguyu çalıştırabilirsiniz

BOTH tabloları için tüm sütunları nasıl bir araya getirdiğimi görün? Ben Rails bu aynı sorguyu çalıştırdığınızda, ancak, istediğim tüm sütunları alamadım - Sadece Profilinden bu haberler:

# 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 

I (verimli) bütün özelliklere sahip bir nesne dönmek istiyorum Profil ve Kullanıcı birlikte. Ben istemiyorum: Kullanıcı eklemek çünkü mantıklı değil. Kullanıcı her zaman en son profilin bir parçası olmalıdır, onlar Profil modelinde alanlarmış gibi. Bunu nasıl başarabilirim?

Sana Raylar katılmak kullanıcılara ve profilleri yükleyebilir sanmıyorum

+0

Kullanıcı alanlarının neden profil modelinin içinde olmasını istersiniz? Açıkça iki ayrı model, profil ve kullanıcı var. İçeriklerini kullanarak, her iki varlık için de veriyi tek bir sorguda getirebilir ve sonra sadece bir profil yapamazsınız. – aromero

+0

NOT bir sorgu ...: include iki sorgu üretiyor – sethvargo

cevap

10

... sorun Profili modeli Kullanıcı için özellikleri içermediğinden gerçeği ile ilgili bir şey olduğunu düşünüyorum. Rails'in önceki sürümlerinde (< 2.1) ilişkili modellerin yüklemelerinin birleştirmelerle yapıldığını düşünüyorum, ancak bu verimli değildi. Here, bazı materyallere ve açıklamalara sahipsiniz.

Açıkça ifade etseniz bile, buna katılmak istediğinizi söyleseniz de, Raylar ilişkili modeller ile eşleştirmez. Yani Profile.whatever_here diyorsanız, her zaman Profile nesnesine eşlenecektir.

hala söz konusu, o zaman kendiniz özel sql sorgusu ve süreç sonuçlarını çağırabilir söylediklerini yapmak isterseniz:

p = ActiveRecord::Base.connection.execute("SELECT * FROM profiles JOIN users ON profiles.user_id = users.id LIMIT 1") 

ve aldığı satırın tarafından sonucu satırının olsun:

p.fetch_row 

Bir diziye zaten eşleşecek. Eğer first_name ve AciveRecord::Relation nesne üzerinde user yöntemini çağırarak çünkü

Kişisel hatalar vardır ve Profile nesneler değil, tek bir nesne dizisi saklar. Bu yüzden, . Sadece bir kayıt getirmesi

daha iyi yolu aramaktır:

p = Profile.joins(:user).first 
p.first_name 
p.user 

Ama p.user çağırdığınızda onu veritabanını sorgular. Bunu önlemek için, include'u kullanabilirsiniz, ancak yalnızca bir profil nesnesini yüklerseniz, yararsızdır. Bir seferde çok sayıda profil yüklerseniz ve kullanıcı tablosunu dahil etmek istiyorsanız bir fark yaratacaktır.

17

Seçmek istediğiniz sütunları adlandırmak için select() öğesini kullanın. En azından bu Rails 3.0.9'da çalışıyor.

Arka plan: Uygulamamın birincil bir tablosu var: haklar. Bir etiket ve renk vermek istedim: verilen bir kayıt: bir indeks listesinden kolayca seçebilmem için. Bu, ilgili kayıtların Rails resmine uymuyor; Çoğu: haklar asla etiketlenmeyecek ve etiketler tamamen keyfi (tag/edit yoluyla kullanıcı girişi).

Etiket verilerini şu şekilde kopyalamayı deneyebilirim: doğru kayıt, ancak normal formu ihlal ediyor. Ya da sorgulamayı deneyebilirim: her biri için etiketler: doğru kayıt, ama bu acı verici verimsiz bir yaklaşımdır. Masalara katılabilmek istiyorum. Ben görünümler/hak/index.html.erb içinde etiketadı ve TagColor kullanacağım

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 |    | 
+------------+--------------+------+-----+---------+----------------+ 

, bu yüzden @rights bunu itiraz bu sütunları dahil etmek haklar denetleyicisi istiyorum:

MySQL konsolu gösterir manzaraya geçer. değil her yana: sağ bir var etiketi, ben bir dış kullanmak istiyorum katılmak: Herkes bulduğu gibi

@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id") 

Ama yalnız bu işe yaramazsa: etiketadı bir blok referansı bir sunucu hatası üretir. Sonunda seçkin eklemek Ancak, her şey yolunda:

@rights = Right.joins("LEFT OUTER JOIN tags ON rights.Tagid = tags.id").select("rights.*,tags.TagName as TagName,tags.TagColor as TagColor") 

Not 6/7/13 eklendi: select yan tümce takma adları gerektirmez - Bu çok çalışır: Şimdi

.select("rights.*,tags.TagName,tags.TagColor") 

benim görünümünde etiketadı ve TagColor başvurabilirsiniz: Ben başvuran sonra katılmak olduğunu veritabanındaki bir vIEW oluşturma ve bu soruna yuvarlak var

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

Konsolu '@ rights' yazmanın konsolda görüntülenmeyeceğini unutmayın. ekstra etiket elemanları. Ancak '@ rights.TagName 'yazarak değerleri gösterecektir. – Doug

+0

Rails tembel yükleme nedeniyle düşünüyorum; veritabanı, belirli bir sütun değeri gerekli olana kadar aslında okunmaz. –

2

o kodda normal ActiveRecord tablo sanki o . Bu, veri tabanından veri almak için iyidir, ancak güncellemeniz gerekirse, 'gerçek' tabloları temsil eden temel sınıflara geri dönmeniz gerekir. Ben biggish tabloları kullanan raporları yaparken bu yöntemi kullanışlı buldum - verileri tek bir isabetle alabilirsiniz. Bu ActiveRecord içine inşa edilmiş gibi görünmüyor, bana açık bir şey gibi görünüyor şaşırıyorum! Böylece sizin için

: YAKUT modelleri dosyanın İÇİNDE

CREATE VIEW User_Profiles 
AS 
SELECT P.*, U.first_name 
FROM Users U 
inner join Profiles P on U.id=P.user_id 

:

class UserProfile < ActiveRecord::Base 
    self.primary_key = :id 
    #same dependencies as profiles 
end 

** İPUCU ... Hep bakış sahibini ayarlamayı unutmayın SQL İÇİNDE

(Postgres kullanıyorum), bu yüzden çok lanetleme ve kendini suçlama ile hemen patlar.

3

Bu durumda select("*").joins(:table)

kullanmayı deneyin, şunları yazın: sizin için çalışan

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

Umut.

3

Bu ipuçlarını okuduktan sonra, 3 ways to do eager loading (preloading) in Rails 3 & 4 öğelerini okuyarak bir sorguya tümünün yüklenmesini tamamladım.

Ben Rails 4 kullanıyorum ve bu benim için bir cazibe gibi çalıştı:

refs = Referral.joins(:job) 
      .joins(:referee) 
      .joins(:referrer) 
      .where("jobs.poster_id= ?", user.contact_id) 
      .order(created_at: :desc) 
      .eager_load(:job, :referee, :referrer) 

İşte benim çalışmalarda yapılmıştır.

#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 :) 
İlgili konular