Ruby on rails-odwołaj się do tego samego modelu dwa razy?

Czy możliwe jest ustawienie podwójnej relacji w modelach activerecord za pomocą polecenia generate scaffold?

Na przykład, gdybym miał model User i model PrivateMessage, tabela pm musiałaby śledzić zarówno sender, jak i recipient.

Oczywiście, dla jednego związku zrobiłbym to:

ruby script/generate scaffold pm title:string content:string user:references

Czy istnieje podobny sposób na ustanowienie dwóch relacji?

Poza tym, czy w ogóle można ustawić aliasy dla relacji?

Więc zamiast powiedzenie:

@message.user

Możesz użyć czegoś w rodzaju:

@message.sender lub @message.recipient

Każda rada byłaby mile widziana. Dzięki.
Author: aceofbassgreg, 2010-01-13

4 answers

Dodaj to do swojego modelu

has_one :sender, :class_name => "User"
has_one :recipient, :class_name => "User"

I możesz wywołać @message.sender i @message.recipient i oba odniesienia do modelu użytkownika.

Zamiast user:references w poleceniu Generuj potrzebujesz sender:references i recipient:references

 51
Author: Veger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-03 20:05:05

Oto pełna odpowiedź na ten problem, na wypadek, gdyby ludzie odwiedzający to pytanie byli nowi w Ruby on Rails i mieli trudności ze złożeniem wszystkiego do kupy (tak jak wtedy, gdy po raz pierwszy przyjrzałem się temu zagadnieniu).

Niektóre części rozwiązania mają miejsce w Twoich migracjach, a niektóre w modelach:

Migracje

class CreatePrivateMessages < ActiveRecord::Migration
  def change
    create_table :private_messages do |t|
      t.references :sender
      t.references :recipient
    end
    # Rails 5+ only: add foreign keys
    add_foreign_key :private_messages, :users, column: :sender_id, primary_key: :id
    add_foreign_key :private_messages, :users, column: :recipient_id, primary_key: :id
  end
end

Tutaj podajesz, że są dwie kolumny w tej tabeli, które będą określane jako: sender i: recipient i które zawierają odniesienia do innej tabeli. Rails utworzy dla Ciebie kolumny o nazwach 'sender_id' i 'recipient_id'. W naszym przypadku będą one każdym wierszem odniesienia w tabeli Users, ale określamy to w modelach, a nie w migracjach.

Modele

class PrivateMessage < ActiveRecord::Base
  belongs_to :sender, :class_name => 'User'
  belongs_to :recipient, :class_name => 'User'
end

Tutaj tworzysz właściwość na modelu PrivateMessage o nazwie: sender, a następnie określasz, że ta właściwość jest powiązana z klasą użytkownika. Rails, widząc "belongs_to: sender", będzie szukał kolumny w bazie danych o nazwie "sender_id", którą zdefiniowaliśmy powyżej i użyj go do przechowywania klucza obcego. Więc robisz dokładnie to samo dla odbiorcy.

To pozwoli ci uzyskać dostęp do nadawcy i odbiorcy, obu instancji modelu użytkownika, poprzez instancję modelu PrivateMessage, jak to:

@private_message.sender.name
@private_message.recipient.email

Oto twój model użytkownika:

class User < ActiveRecord::Base
  has_many :sent_private_messages, :class_name => 'PrivateMessage', :foreign_key => 'sender_id'
  has_many :received_private_messages, :class_name => 'PrivateMessage', :foreign_key => 'recipient_id'
end

Tutaj tworzysz właściwość na modelu Użytkownika o nazwie :sent_private_messages, określając, że ta właściwość jest powiązana z Modelem PrivateMessage i że klucz obcy w modelu PrivateMessage, który odnosi się do tej właściwości, nazywa się "sender_id". Następnie robisz to samo dla otrzymanych prywatnych wiadomości.

To pozwala na uzyskanie wszystkich użytkowników wysłanych lub odebranych prywatnych wiadomości, robiąc coś takiego:

@user.sent_private_messages
@user.received_private_messages

Wykonanie jednej z nich zwróci tablicę instancji modelu PrivateMessage.

....

 101
Author: Richard Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-30 22:19:42

Cześć. aby mieć obie strony relacji zrobić jak poniżej w obu modelach:

class Message < ActiveRecord::Base

 belongs_to     :sender,
                :class_name => "User",
                :foreign_key  => "sender_id"

 belongs_to     :recipient,
                :class_name => "User",
                :foreign_key  => "recipient_id" 
end

class User < ActiveRecord::Base

  has_many      :sent, 
                :class_name => "Message",
                :foreign_key  => "sent_id"

  has_many      :received, 
                :class_name => "Message", 
                :foreign_key  => "received_id"
end
Mam nadzieję, że to ci pomoże...
 16
Author: radmehr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-23 12:43:59

Powyższe odpowiedzi, choć doskonałe, nie tworzą ograniczeń klucza obcego w bazie danych, zamiast tego tworzą tylko indeksy i kolumny bigint. Aby upewnić się, że ograniczenie klucza obcego jest egzekwowane, dodaj następujące elementy do migracji:

class CreatePrivateMessages < ActiveRecord::Migration[5.1]
    def change
        create_table :private_messages do |t|
          t.references :sender
          t.references :recipient
        end

        add_foreign_key :private_messages, :users, column: :sender_id, primary_key: :id
        add_foreign_key :private_messages, :users, column: :recipient_id, primary_key: :id
    end
end

Zapewni to, że indeksy zostaną utworzone na sender_id i recipient_id, a także na ograniczeniach klucza obcego w bazie danych, której używasz.

 8
Author: bbengfort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-13 01:50:57