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