Ruby on rails - Reference the same model twice?

前端 未结 4 1640
长情又很酷
长情又很酷 2020-11-30 18:10

Is it possible to set up a double relationship in activerecord models via the generate scaffold command?

For example, if I had a User

相关标签:
4条回答
  • 2020-11-30 18:50

    Here's a complete answer to this issue, in case people visiting this question are new to Ruby on Rails and having a hard time putting everything together (as I was when I first looked into this).

    Some parts of the solution take place in your Migrations and some in your Models:

    Migrations

    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
    

    Here you are specifying that there are two columns in this table that will be referred to as :sender and :recipient and which hold references to another table. Rails will actually create columns called 'sender_id' and 'recipient_id' for you. In our case they will each reference rows in the Users table, but we specify that in the models, not in the migrations.

    Models

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

    Here you are creating a property on the PrivateMessage model named :sender, then specifying that this property is related to the User class. Rails, seeing the "belongs_to :sender", will look for a column in your database called "sender_id", which we defined above, and use that to store the foreign key. Then you're doing the exact same thing for the recipient.

    This will allow you to access your Sender and Recipient, both instances of the User model, through an instance of the PrivateMessage model, like this:

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

    Here is your User Model:

    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
    

    Here you are creating a property on the User Model named :sent_private_messages, specifying that this property is related to the PrivateMessage Model, and that the foreign key on the PrivateMessage model which relates it to this property is called 'sender_id'. Then you are doing the same thing for received private messages.

    This allows you to get all of a users sent or received private messages by doing something like this:

    @user.sent_private_messages
    @user.received_private_messages
    

    Doing either of these will return an array of instances of the PrivateMessage model.

    ....

    0 讨论(0)
  • 2020-11-30 18:53

    Add this to your Model

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

    And you are able to call @message.sender and @message.recipient and both reference to the User model.

    Instead of user:references in your generate command, you'd need sender:references and recipient:references

    0 讨论(0)
  • 2020-11-30 19:02

    hi there to have both side relation do as bellow in your both models:

    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
    

    I hope this help you...

    0 讨论(0)
  • 2020-11-30 19:10

    The above answers, while excellent, do not create foreign key constraints in the database, instead only creating indexes and bigint columns. To ensure that the foreign key constraint is enforced, add the following to your migration:

    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
    

    This will ensure that the indices get created on the sender_id and recipient_id as well as the foreign key constraints in the database you're using.

    0 讨论(0)
提交回复
热议问题