W moim projekcie Rails 3 mam model użytkownika z samoodnośnym sprzężeniem za pomocą następującego modelu. Chcę użyć tej tabeli łączenia, aby znaleźć aktywność związaną z obserwowanym użytkownikiem. Prawie wszystko mam poprawnie skonfigurowane, z wyjątkiem tego, że zapytanie wygenerowane przez sprzężenie całkowicie ignoruje opcję :primary_key w modelu sprzężenia.

Oto odpowiedni schemat dla odpowiednich modeli:

  create_table "users", :force => true do |t|
    t.string   "email",                                 :default => "",    :null => false
    t.string   "first_name"
    t.string   "last_name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "follows", :force => true do |t|
    t.integer  "user_id"
    t.integer  "followed_user_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "activities", :force => true do |t|
    t.integer  "user_id"
    t.text     "body"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

Oto skojarzenia w modelach

class User < ActiveRecord::Base
    has_many :follows
    has_many :followed_users, :through => :follows
  has_many :followed_activities, :through => :follows
    has_many :activities
end
class Follow < ActiveRecord::Base
    belongs_to :user
    belongs_to :followed_user, :class_name => "User"
    has_many :followed_activities, :primary_key => :followed_user, :foreign_key => :user_id, :class_name => "Activity"
end

Poniższa praca jest w porządku:

u = User.first
u.follows # returns corresponding records from the follows table
u.followed_users # returns all users that u is following
u.followed_users.first.activities # returns all activity records corresponding to the first person the user is following
Follow.first.activities # same as the previous

Jednak poniższe po prostu zwraca pustą tablicę:

u.followed_activities

Oto sql, który jest generowany z ostatniej instrukcji:

  Activity Load (0.2ms)  SELECT `activities`.* FROM `activities` INNER JOIN `follows` ON `activities`.user_id = `follows`.id WHERE ((`follows`.user_id = 1))

Powodem, dla którego nie działa, jest to, że próbuje dołączyć, użyj pliku „follows”.id jako klucza podstawowego, a nie „follows”.followed_user.

Czy to błąd, czy muszę powtórzyć deklarację :primary_key gdzieś w modelu użytkownika? Nie mogę znaleźć żadnej wzmianki w interfejsie Rails api ani nigdzie indziej w Internecie.

Wersja szyn: 3.0.7

1
Justin 16 lipiec 2011, 06:20

2 odpowiedzi

Najlepsza odpowiedź

Justin, masz 2 skojarzenia o nazwie „obserwowane_działania”. oczywiście mają inny kontekst (różne modele), ale chciałbym prosić o wypróbowanie metody w bloku asocjacyjnym w następujący sposób:

has_many :followed_users, :through => :follows do
  def activities
  end
end
0
Anatoly 16 lipiec 2011, 10:38
Dobra uwaga na temat posiadania „obserwowanych_działań” w dwóch modelach. Umieściłem skojarzenie tylko w następującym modelu, ponieważ był to jedyny sposób, w jaki mogłem wymyślić, jak uruchomić moje skojarzenie has_many :through (nie mogłem uruchomić tutaj deklaracji :source). Próbuję wymyślić, jak sprawić, by działał z blokiem asocjacyjnym, jak wspomniałeś. Co umieściłbym w bloku? Metoda wyszukiwania?
 – 
Justin
16 lipiec 2011, 12:05
Tak, znajdź metodę lub iterator, jeśli chcesz zebrać tablicę. pierwotny pomysł na umieszczenie metod wewnątrz skojarzeń był w tej książce Zaawansowane przepisy Rails
 – 
Anatoly
16 lipiec 2011, 14:38
Zapomniałem, że mam tę książkę! Używając innej sztuczki z książki, wyjaśniłem nieco pomysł. Nie wiem, jak to zrobić w komentarzach, więc trochę zaktualizowałem Twój post.
 – 
Justin
17 lipiec 2011, 02:28

Uważam, że intuicyjne jest tworzenie relacji łańcuchowych z klejnotem „nested_has_many_through”, http://rubygems.org/gems/ nested_has_many_through, który będzie standardową częścią rails 3.1 i może dać ci kolejne narzędzie do rozwiązania tego problemu tutaj

Pozwoli ci to zrobić coś takiego:

class Author < User
  has_many :posts
  has_many :categories, :through => :posts, :uniq => true
  has_many :similar_posts, :through => :categories, :source => :posts
  has_many :similar_authors, :through => :similar_posts, :source => :author, :uniq => true
  has_many :posts_of_similar_authors, :through => :similar_authors, :source => :posts, :uniq => true
  has_many :commenters, :through => :posts, :uniq => true
end

class Post < ActiveRecord::Base
  belongs_to :author
  belongs_to :category
  has_many :comments
  has_many :commenters, :through => :comments, :source => :user, :uniq => true
end

To bardzo uprościło moje zapytania i kolekcje. Mam nadzieję, że znajdziesz odpowiedź na swój problem, jest to trudne!

1
thejonster 16 lipiec 2011, 10:23
Jeśli nie będę miał innych opcji, spróbuję połączyć moje zapytanie w łańcuch za pomocą metody, którą opisujesz (user.followed_users.activities), ale sposób, w jaki to ustrukturyzowałem, jest tylko prostym has_many :through. Jedyną różnicą jest to, że używam niestandardowego klucza podstawowego w tabeli sprzężenia.
 – 
Justin
16 lipiec 2011, 10:21
Fajnie, dziękuję! Nie wiedziałem, że dodali to do 3.1. has_many -> :through -> :source było właśnie tym, czego potrzebowałem, aby moje złożone zapytania działały bez uciekania się do ogromnych instrukcji SQL.
 – 
poetmountain
1 marzec 2012, 09:04