I am writing a rails application with conversations between clients and administrators. And i want the administrators respond to questions sent it by clients.
The administrators should be able to see the previous conversations with a reply box.
What is the best way to save these coversations:
Single table with marks of question and answer and view them as table entries?
Different tables and simply organise them by time?
class Administrator < ActiveRecord::Base
has_many :messages, as: :author
end
class Client < ActiveRecord::Base
has_many :messages, as: :author
end
class Message < ActiveRecord::Base
belongs_to :author, polymorphic: true
belongs_to :chat
end
class Chat < ActiveRecord::Base
has_many :messages
belongs_to :client
belongs_to :administrator
end
If you want to show messages of a particular chat you can do it this way:
#chat = Chat.find_by_client_id_and_administrator_id(client_id, administrator_id)
#messages = #chat.messages.order(:created_at)
If client and administrator belong to the same model, for instance User, then:
class User < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :chat
end
class Chat < ActiveRecord::Base
has_many :messages
belongs_to :client, class_name: "User"
belongs_to :administrator, class_name: "User"
end
Related
I would like a user be able to create a course(so it should belong to one user) and also be able to join another course that it haven't created by him.What is the proper associations between the course and the user ? I want to make the following model associations:
Class User < ActiveRecord::Base
has_many :courses
has_many :comments ,through: :courses
end
Class Course < ActiveRecord::Base
has_and_belongs_to_many :users #here i am not sure
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :courses
end
I think what you should be able to do something like:
Class User < ActiveRecord::Base
has_many :courses
has_many :course_users
has_many :subscribed_courses, through: :course_users, source: :course # I think you should be able to do foreign_key: :course_id, class_name: 'Course'
has_many :comments ,through: :courses
end
Class Course < ActiveRecord::Base
belongs_to :user
has_many :course_users
has_many :participants, through: :course_users, source: :user # I think you should be able to do foreign_key: :user_id, class_name: 'User'
has_many :comments
end
Class Comment < ActiveRecord::Base
belongs_to :courses
end
#course_users is a join table for courses and users
class CourseUser < ActiveRecord::Base
# inside here you could have several other connections e.g grade of a user in a course within this join model
belongs_to :user
belongs_to :course
end
If I'm understanding what you're saying - you need to have a third model - you can call it enrollment
For Course you would use belongs_to :user if each course is created as a user.
Your Enrollment model with have two HABTAM
Class Enrollment < ActiveRecord::Base
has_and_belongs_to_many :users
has_and_belongs_to_many :courses
end
(An Aside, if a course is going to be offered more than once, you'll have to add an additional model for each instance of the course and the enrollment will belong to that model, and not courses)
I have two models: Users and Posts. The way I have things setup, a post belongs to an owner (i.e. user) and also has many participants (i.e. users). In my User model I'd like to ensure that an owner never belongs to a post. I've done this in the front-end but found more code than need-be.
This led me to believe that using conditions would be an ideal solution. I've seen SQL conditions used in this manner but didn't know exactly what the best way to get this done for an ownership scenario. Suggestions?
class User < ActiveRecord::Base
has_many :posts
# belongs_to :posts, conditions: ...
end
class Post
has_many :participants, class_name: "User", foreign_key: "user_id"
belongs_to :owner, class_name: "User", foreign_key: "user_id"
end
To acheive this, I think you need a third model. If you set things up as follows it should work:
User model:
class User < ActiveRecord::Base
has_many :posts # This is the other side of your owner association
has_many :user_posts # This is your link table for participants
has_many :participations, through: :user_posts, source: :user # These are the posts the user is a participant in
end
Post model:
class Post < ActiveRecord::Base
has_many :user_posts, ->(p) { where.not(user_id: p.user_id) } # Here is your condition for the participants
has_many :participants, through: :user_posts, source: :user
belongs_to :owner, class_name: "User", foreign_key: "user_id"
end
UserPost model:
class UserPost < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
As #Oxynum's answer makes clear, you should also think about putting a validation in the UserPost model to prevent the participant from being saved if he is also the owner:
validate :participant_cannot_be_owner
def participant_cannot_be_owner
if user == post.try(:owner)
errors.add(:user_id, "can't be the owner of the post")
end
end
First, there is probably an error in your associations, cause it seems like you need a join table for the participants relationship.
You should probably use a http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
has_many through association.
Something like this :
class User < ActiveRecord::Base
has_one :owned_post, class_name: "Post", foreign_key: :owner_id
has_many :participations
has_many :posts, through: :participations
end
class Participation < ActiveRecord::Base
belongs_to :post
belongs_to :participant, class_name: "User"
end
class Post < ActiveRecord::Base
belongs_to :owner, class_name: "User"
has_many :participants, through: :participations
end
When you have this model, you can use a validation on the participation model to prevent an owner to be a participant. By using a custom validation : http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
class Participation < ActiveRecord::Base
belongs_to :post
belongs_to :participant, class_name: "User"
validate :participant_is_not_the_owner
def participant_is_not_the_owner
if participant == post.owner
errors.add(:participant, "can't be the owner")
end
end
end
The Ruby on Rails app I am working on allows users to create and share agendas with other users.
In addition, we must be able to:
Display a list of agendas for each user, on his profile
Display a list of users associated with an agenda, on the agenda's page
When sharing an agenda with another user, define a role for this user, and display the role of this user on the list mentioned right above
I was going to go with a has_and_belongs_to_many association between the user and the agenda models, like that:
class User < ActiveRecord::Base
has_and_belongs_to_many :agendas
end
class Agenda < ActiveRecord::Base
has_and_belongs_to_many :users
end
But then I wondered whether this would let me get and display the #user.agenda.user.role list of roles on the given agenda page of a given user.
And I thought I should probably go with a has_many :through association instead, such as:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
And although I was pretty comfortable about the idea of a user having several roles (one for each agenda), I am not sure about the idea of an agenda having several roles (one for each user?).
Finally, to add to the confusion, I read about the polymorphic association and thought it could also be a viable solution, if done this way for instance:
class Role < ActiveRecord::Base
belongs_to :definition, polymorphic: true
end
class User < ActiveRecord::Base
has_many :roles, as: :definition
end
class Agenda < ActiveRecord::Base
has_many :roles, as: :definition
end
Does any of the above solutions sound right for the situation?
UPDATE: Doing some research, I stumbled upon this article (from 2012) explaining that has_many :through was a "smarter" choice than has_and_belongs_to_many. In my case, I am still not sure about the fact that an agenda would have many roles.
UPDATE 2: As suggested in the comments by #engineersmnkyn, a way of solving this would be to go with two join tables. I tried to implement the following code:
class User < ActiveRecord::Base
has_many :agendas, through: :jointable
end
class Agenda < ActiveRecord::Base
end
class Role < ActiveRecord::Base
end
class Jointable < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :agendaroles through :jointable2
end
class Jointable2 < ActiveRecord::Base
belongs_to :roles
belongs_to :useragenda
end
I am not sure about the syntax though. Am I on the right track? And how should I define the Agenda and the Role models?
UPDATE 3: What if I went with something like:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
and then, in the migration file, go with something like:
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.belongs_to :user, index: true
t.belongs_to :agenda, index: true
t.string :privilege
t.timestamps
end
end
end
Would I be able to call #user.agenda.privilege to get the privilege ("role" of creator, editor or viewer) of a given user for a given agenda?
Conversely, would I be able to call #agenda.user.privilege ?
Okay I will preface by saying I have not tested this but I think one of these 2 choices should work well for you.
Also if these join tables will never need functionality besides a relationship then has_and_belongs_to_many would be fine and more concise.
Basic Rails rule of thumb:
If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.
First using your example (http://repl.it/tNS):
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda:agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user_agenda
end
This uses a join table to hold the relationship of User <=> Agenda and then a table to join UserAgenda => Role.
The Second Option is to use a join table to hold the relationship of User <=> Agenda and another join table to handle the relationship of User <=> Agenda <=> Role. This option will take a bit more set up from a CRUD standpoint for things like validating if the user is a user for that Agenda but allows a little flexibility.
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda: agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user
belongs_to :agenda
end
I know this is a long answer but I wanted to show you more than 1 way to solve the problem in this case. Hope it helps
I am new to Rails (and programming) and after going through a few tutorials, I am designing a messaging app to test my skills.
The situation I am modelling is where a user can message 2+ other users. Here's what I came up with
A conversation has many participants (users) and many messages
(message).
A user has many conversation and many messages.
A message belongs to users (sender + recipients) and belongs to a conversation.
The ActiveRecord model is then:
class User < ActiveRecord::Base
has_many :messages, :through :conversation
has_many :conversations # or is belongs_to :conversation
end
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
class Conversation < ActiveRecord::Base
has_many :messages
belongs_to :user # or is it has_many :users
end
Or do I have to add a 4th interface inbox
class Inbox < ActiveRecord::Base
belongs_to :user
has_many :conversations
end
and I would change the user and conversation models to be
class User < ActiveRecord::Base
has_one :inbox
has_many :conversations, :through :inbox
has_many :messages, :through :conversation
end
class Conversation < ActiveRecord::Base
belongs_to :inbox
has_many :messages
belongs_to :users
end
The second option looks redundant.
So yeah, I am fuzzy about the relationship/association between a conversation and users. All input to enlighten me is greatly appreciated.
Your first way is better in my opinion, but it should look like this:
class User < ActiveRecord::Base
has_many :messages
has_many :user_conversations
has_many :conversations, through: :user_conversations
end
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
class Conversation < ActiveRecord::Base
has_many :messages
has_many :user_conversations
has_many :users, through: :user_conversations
end
# join table between users and conversations
class UserConversation < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
The reason is that a user can have many conversations, and a conversation can have many users. You need to create the join table UserConversation to accommodate this.
Also, the easiest way to find out which model should belong to the other model is to ask which model should have the foreign key of the other model. The one with the foreign keys belongs_to the other model.
I'm a new to rails but I have a big problem with my app.
Business Logic
- User can favorite restaurants, menus, items.
We have :
class Restaurant < ActiveRecord::Base
has_many :items, :dependent=>:destroy
has_many :menus, :dependent=> :destroy
belongs_to :owner, :class_name => 'User'
end
class Menu < ActiveRecord::Base
belongs_to :restaurant
has_many :items,:dependent=>:destroy
end
class Item < ActiveRecord::Base
belongs_to :restaurant
belongs_to :menu
end
class User < ActiveRecord::Base
has_many :restaurants
end
Could someone help me resolve my problem ?
Thanks for your support
p/s: Sorry for my english, i'm vietnamese.
You need to build a polymorphic association between a User and a Favoritable item. This is done using polymorphic association bellow:
class Restaurant < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
end
class Menu < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
end
class Item < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
end
class User < ActiveRecord::Base
has_many :favorites, as: :favoritable
end
Then you can retrieve user's favorites with the following:
user = User.first
user.favorites
# => [...]
You can build a new favorite using:
user.favorites.build(favorite_params)
Or you can assign a favoritable object directly using:
user.favorites << Restaurant.find(1)
user.favorites << Menu.find(1)
user.favorites << Item.find(1)
More information about polymorphic associations.