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!
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
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)