users dialogs database scheme - ruby-on-rails

I want to create users dialog
How I must do?
Create one record with sender_id and recipient_id and then "select * from table_dialog where sender_id=current.id or recipient_id =current.id" also add 2 columns deleted_by_sender and deleted_by_recipient
Or create 2 record in database for each dialog
What is the best solution? Or propose your own solution please

If by "dialog" you mean a "conversation between TWO participants", then it is very similar to classic mailbox. The following code extract(with abbreviation) from one of my project which implements similar functionality. Maybe will be helpful.
class User < ActiveRecord::Base
# ....
has_many :received_messages, :class_name => "Message", :foreign_key => 'recipient_id'
has_many :sent_messages, :class_name => "Message", :foreign_key => 'sender_id'
# ....
end
class Message < ActiveRecord::Base
validates :content, :presence => true
validates :sender, :presence => true, :associated => true
validates :recipient, :presence => true, :associated => true
belongs_to :sender, :class_name => 'User', :foreign_key => 'sender_id'
belongs_to :recipient, :class_name => 'User', :foreign_key => 'recipient_id'
default_scope order('created_at desc')
# usage: user.received_messages.unread
scope :unread, where('unread = true')
def self.chat_between(first_user, second_user)
where('(recipient_id = ? AND sender_id = ?) OR (recipient_id = ? AND sender_id = ?)',
first_user.id, second_user.id, second_user.id, first_user.id)
end
def self.read_all!
self.update_all('unread = false')
end
def read!
self.update_attribute :unread, false
end
def new?(user)
(recipient == user) && (unread == true)
end
end

Related

Translating Database Models to Models on Ruby On Rails

I am beginning Ruby On Rails through a purchase/resale platform project at school. I'm having an issue with my models when I try to translate them from my relational model.
Firstly, I've modelled my database. Here is simplified the entity-relationship model :
I've then translated it in a relational model :
Finally, I've implemented it in Ruby On Rails.
I've implemented a model Client :
class Client < ApplicationRecord
attr_accessor :name
validates :name, :presence => true
has_many :purchasings, :dependent => :destroy
has_many :sellers, :through => :purchasings
has_many :articles, :through => :purchasings
end
I've implemented a model Seller :
class Seller < ApplicationRecord
attr_accessor :name
validates :name, :presence => true
has_many :purchasings, :dependent => :destroy
has_many :sellers, :through => :purchasings
has_many :articles, :through => :purchasings
end
I've implemented a model Article
class Article < ApplicationRecord
attr_accessor :quantity
validates :quantity, :presence => true
has_one :purchasing, :dependent => :destroy
has_one :client, :through => :purchasings
has_one :seller, :through => :purchasings
end
I've implemented a model Purchasing :
class Purchasing < ApplicationRecord
attr_accessor :client_id, :seller_id, :article_id
belongs_to :client, :class_name => "Client"
belongs_to :seller, :class_name => "Seller"
belongs_to :article, :class_name => "Article"
validates :client_id, :presence => true
validates :seller_id, :presence => true
validates :article_id, :presence => true
end
I've modified the Purchasing database migration :
class CreatePurchasing < ActiveRecord::Migration[5.1]
def change
[...]
add_index :purchasings, :client_id
add_index :purchasings, :seller_id
add_index :purchasings, :article_id
add_index :purchasings, [:client_id, :seller_id], :unique => true
end
def down
[...]
end
end
I know this is incorrect because when I execute the following code on the Rails console :
cl1 = Client.create(:name => "John")
cl2 = Client.create(:name => "James")
sel1 = Seller.create(:nom => "Jack")
sel2 = Seller.create(:nom => "Jil")
a1 = Article.create(:quantity => 5)
p1 = Purchasing.new(:client => cl1, :client_id => cl1.id, :seller => sel1, :seller_id => sel1.id, :article => a1, :article_id => a1.id)
p1.save
p2 = Purchasing.new(:client => cl2, :client_id => cl2.id, :seller => sel1, :seller_id => sel1.id, :article => a1, :article_id => a1.id)
p2.save
p2.save returns true whereas an article can't be sold by a same seller and bought by two clients different.
You are adding the index on incorrect columns on purchasings table. As per the requirement, the article_id and seller_id should not get repeated ideally. So you actually need is a uniqueness constraint on seller_id, and article_id column. You can do so by creating an unique index on the composition of two columns seller_id, and article id on the database layer. You should also add the application layer validation on the purchasing model.
class Purchasing < ApplicationRecord
attr_accessor :client_id, :seller_id, :article_id
belongs_to :client, :class_name => "Client"
belongs_to :seller, :class_name => "Seller"
belongs_to :article, :class_name => "Article"
validates :client_id, :presence => true
validates :seller_id, :presence => true
validates :article_id, :presence => true
validates :article_id, uniqueness: {scope: :seller_id}
end
Now you should also write a database migration to add the unique index on these two columns.
class AddUniquenessConstraintInPurshasing < ActiveRecord::Migration
def change
add_index :purchasings, [:article_id, :seller_id], :unique => true
end
end

Filtering Association By Another Association

I have a friendship model that contains a status.
class Friendship < ActiveRecord::Base
attr_accessible :friend_id, :user_id, :source_id
after_create :check_friend_status
# Relationships
belongs_to :user, :touch => true
belongs_to :friend, :class_name => "User", :touch => true
belongs_to :source
has_one :status, :class_name => "FriendStatusDescriptor", :foreign_key => 'friendship_id'
validates_uniqueness_of :user_id, :scope => [:friend_id, :source_id]
def check_friend_status
# Check user/friend for existing friend status
if FriendStatusDescriptor.find(:first, :conditions => ["friendship_id = ?", self.id]).nil?
status = FriendStatusDescriptor.new
status.friendship_id = self.id
status.save
end
end
end
class FriendStatusDescriptor < ActiveRecord::Base
attr_accessible :alert, :friendship_id, :hide
belongs_to :friendship
validates_uniqueness_of :friendship_id
end
The status model has a boolean variable called hide. I want to be able to filter my user's friendships by the ones with hide set to false. Something along these lines.
# In User Model
# Friendships
has_many :friendships do
def visible
# Where !friendship.status.hide
end
end
So that in my controller I can just do this
user.friendships.visible
I'm not sure how to access the individual friendship in this method though.
I think you want:
class User
has_many :friendships,
:class_name => "FriendStatusDescriptor",
:foreign_key => 'friendship_id'
If you want to filter visible and non-visible friendships by separete you can add scopes to Friendship model:
class Friendship
scope :visible, -> { joins(:status).where("friend_status_descriptors.hide = ?", false) }
Then apply that scope:
user.friendships.visible

rails counter cache and foreign key test

This is my favorite designer model
favorite_designer.rb
class FavoriteDesigner < ActiveRecord::Base
belongs_to :user, :counter_cache => true
belongs_to :designer, :class_name => "User", :foreign_key => :designer_id
validates_presence_of :user_id
validates_presence_of :designer_id
validates_numericality_of :user_id, :unless => Proc.new{|f| f.user_id.blank?}
validates_numericality_of :designer_id, :unless => Proc.new{|f| f.designer_id.blank?}
end
How can I test :counter_cache => true and :foreign_key => :designer_id in rspec with shoulda?
You can use counter_cache and with_foreign_key shoulda matchers :
it { should belong_to(:organization).counter_cache(true) }
it { should have_many(:worries).with_foreign_key('worrier_id') }
For full doc and examples look at :
Counter cache doc
Foreign key doc

AR joined class in parent class

i have Author entity which belongs_to User. User has_many posts. Please advice how can i show recent_posts on Author entity from User.
class User < ActiveRecord::Base
has_many :posts, :foreign_key => "author_id"
end
class Post < ActiveRecord::Base
attr_accessible :title, :content
belongs_to :author, :class_name => "User"
end
class Author < ActiveRecord::Base
belongs_to :user
has_many :recent_posts, :through => :user,
:class_name => "Post",
:limit => 3,
:order => "updated_at desc"
end
How recent_post should be done? Raw sql?
You want the :source option to has_many, which you use to specify the association on the other model, like so:
has_many :recent_posts, :through => :user, :source => :posts, :limit => 3, :order => 'updated_at desc'

Last with a custom column name

I have my model defined like this:
class Animal < ActiveRecord::Base
mount_uploader :picture, PictureUploader
attr_accessible :picture, :born_date, :father_id, :mother_id, :name, :obs, :earring, :animal_type, :animal_type_id, :inseminations
validates :name, :born_date, :presence => true
validates :earring, :presence => true, :if => :should_have_earring?
belongs_to :father, :class_name => "Animal"
belongs_to :mother, :class_name => "Animal"
belongs_to :animal_type
has_one :birth
has_one :sell
has_one :death
has_many :inseminations
end
and
class Insemination < ActiveRecord::Base
attr_accessible :bull_id, :cow_id, :done, :expected_birth_date, :expected_dry_date, :insemination_date, :obs, :rut
validates :bull_id, :presence => true
validates :cow_id, :presence => true
validates :insemination_date, :presence => true
belongs_to :bull, :class_name => "Animal"
belongs_to :cow, :class_name => "Animal"
has_one :birth
has_one :abortion
has_one :dry
end
Good, somewhere, I want to get the last insemination from some animal... so, I do #animal.inseminations.last, it should work, but, it does the select using a animal_id property, that does not exist in insemination model. So I get an error like this:
Mysql2::Error: Unknown column 'inseminations.animal_id' in 'where
clause': SELECT inseminations.* FROM inseminations WHERE
inseminations.animal_id = 1 ORDER BY inseminations.id DESC
LIMIT 1
How can I specify it to searh in cow_id and/or bull_id columns? Is that possible?
Thanks in advance.
I think you have a few different options:
1) Instead of using has_many :inseminations, create two separate has many relationships:
has_many :cow_inseminations, :class_name => 'Insemination', :foreign_key => 'cow_id'
has_many :bull_inseminations, :class_name => 'Insemination', :foreign_key => 'bull_id'
2) Use STI and create subclasses of Animal. You will need to add a type field to Animal for this to work:
class Cow < Animal
has_many :inseminations, :foreign_key => 'cow_id'
end
class Bull < Animal
has_many :inseminations, :foreign_key => 'bull_id'
end
Then you can do Bull.first.inseminations or Cow.first.inseminations
You can specify a foreign key:
has_many :inseminations, :foreign_key => :bull_id
However you can only have one foreign_key, so it doesn't work for the cows.
You can do something like Rails Model has_many with multiple foreign_keys to get it to work. But then in this case, you need:
has_many :bull_inseminations, :foreign_key => :bull_id
has_many :cow_inseminations, :foreign_key => :cow_id
def inseminations
# not sure how you store animal type, but something like
return bull_inseminations if animal_type == "bull"
return cow_inseminations if animal_type == "cow"
end
For other attribute methods, you will need to do something similar if you want to use them, eg:
def inseminations_changed?
bull_inseminations_changed? or cow_inseminations_changed?
end
and similarly with inseminations<<, inseminations=, etc.

Resources