2

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!

John Smith
  • 6,105
  • 16
  • 58
  • 109

2 Answers2

4

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

Polymorphic Association

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
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • thanks for your answer but i think the problem is that i have not only a user model but also a admin model that should be able to communicate with each other! SO ids wont work but in my two models the userame is unique! Maybe you want to edit your answer thanks – John Smith Oct 26 '13 at 12:24
  • You mean like a support ticket system admin can send messages to user etc? – Richard Peck Oct 26 '13 at 12:25
  • Hmm, you might want to make the relation polymorphic then! This is where ActiveRecord gets really exciting. Let me edit my answer – Richard Peck Oct 26 '13 at 12:28
1

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)
Amit Thawait
  • 4,862
  • 2
  • 31
  • 25
  • I tried `Message.where_sender_username(@user.username)` but that also only returnd one record! But now with your code it works – John Smith Oct 26 '13 at 12:13
  • can you say me how i would get messages for example for the user and the reciepient_username(elias)? – John Smith Oct 26 '13 at 12:14