How to get not only single record but all records

2019-07-17 03:36发布

问题:

I wrote this search query, that only returns an single record:

 @messages = Message.find_by_sender_username(@user.username)

 #<Message id: 1, sender_username: "emmanuel", reciepent_username: "elias", body: "Die erste Nachricht", gelesen: "", created_at: "2013-10-26 11:17:53", updated_at: "2013-10-26 11:17:53"> 

Although in my Message model i have two records with the sender_username "emmanuel"

 #<Message id: 1, sender_username: "emmanuel", reciepent_username: "elias", body: "Die erste Nachricht", gelesen: "", created_at: "2013-10-26 11:17:53", updated_at: "2013-10-26 11:17:53"> 
 #<Message id: 2, sender_username: "emmanuel", reciepent_username: "vera", body: "Was soll ich dazu sagen", gelesen: "", created_at: "2013-10-26 11:23:57", updated_at: "2013-10-26 11:23:57">

I think the problem is that i have no real relation between the models:

Admin username:string

User username:string

Message

sender_username:string

reciepent_username:string

body:string

read:boolean

MyQuestion is how i should write a relation between this models, i herad something about forgein_key for such relations but im not 100% sure how to make use of it!

回答1:

Rails uses relational databases through a technology called ActiveRecord. This is a type of SQL which basically allows you to "link" tables through a series of relations:

belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many

The way you link your tables is dependant on how the relationship is built, but in your case, you'd use something like this:

Ruby on rails - Reference the same model twice?

#app/models/message.rb
has_one :sender, :class_name => 'User', :foreign_key => 'sender_id'
has_one :recipient, :class_name => 'User', :foreign_key => 'recipient_id'


#app/models/user.rb
has_many :sent_messages, :class_name => 'Message', :foreign_key => 'sender_id'
has_many :received_messages, :class_name => 'Message', :foreign_key => 'recipient_id'

You'll have to edit your tables to have a foreign key column for each relation. You've kind-of done this already, but you need to know that a foreign key is always an ID. So instead of sender_username, you'd have sender_id

This is because the primary key is always a unique ID, which means that ID can be used to identify the record's associations in other tables; meaning you'll be able to reference the record in any query you perform


This will allow you to do this:

@messages = @user.received_messages

Instead of having to mess around with 100's of different queries


Update

If you want to include Admin messages into the mix, you'd want to include a polymorphic association:

class Message < ActiveRecord::Base
  belongs_to :sendable, polymorphic: true
  belongs_to :receiveable, polymorphic: true
end

class Admin < ActiveRecord::Base
  has_many :sent_messages, :class_name => 'Message', as: :sendable
  has_many :received_messages, :class_name => 'Message', as: :receiveable
end

class User < ActiveRecord::Base
  has_many :sent_messages, :class_name => 'Message', as: :sendable
  has_many :received_messages, :class_name => 'Message', as: :receiveable
end

I don't know if this code will work out of the box, but it is definitely point you in the right direction. The way it works is to give your foreign_key an associated model, which means that you can differentiate between whether an admin or user sent the message.

This means that if you call @messages = @user.received_messages , ActiveRecord will automatically ping the Message model, and pull out the rows where receiveable_id = user.id AND receiveable_type = User


For this to work, you'll need to replace your sender_username & receiver_username with 4 columns:

sendable_id
sendable_type

receiveable_id
receiveable_type


回答2:

find_by_sender_username will always return only the 1st record that is matched.

You should use where to get all the records.

@messages = Message.where(sender_username: @user.username)