How to build a unique database model Ruby on Rails 4 - ruby-on-rails

I currently have three models: two different users models which support the Devise auth gem : community organizer and regular user, and one community events model.
I'm trying to allow the community organizer to create events :
To which users can donate funds to ;
Which users can attend .
I use stripe as the payment gateway. I've setup a controller/model scaffolding for the Event model so far :
class Event < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
belongs_to :org_user #organization_user
has_one :category
end
Here is my organization user model :
class OrgUser < ActiveRecord::Base
extend FriendlyId
friendly_id :username, use: :slugged
has_many :posts
has_many :comments
has_many :events
end
I was told that I may need these particular patterns inside of my events and org_user models
class Event < ActiveRecord::Base
event has_many :attendances
event has_many :users, through: :attendances
end
class OrgUser < ActiveRecord::Base
org_user has_many :attendances
org_user has_many :events, through: :attendances
end
class User < ActiveRecord::Base
end
What is your advice on creating the relationship. I also don't want to forget the User.rb which will sign the form to be a part of the event posted by the :org_user. Only the org_user will have the ability to create/post events. Normal Users will have access to the signup form to attend those events. Please, help me clear this hurdle.

Several things :
The way you right has many through relationship is wrong (see the doc )
You don't model your donation relationship from users to events
You could model things like this :
class Event < ActiveRecord::Base
has_many :attendances
has_many :users, through: :attendances
end
class OrgUser < ActiveRecord::Base
has_many :events # as coordinations
end
class User < ActiveRecord::Base
has_many :donations
has_many :attendances
end
class Attendance < ActiveRecord::Base
belongs_to :user
has_one :event
end
class Donation < ActiveRecord::Base
belongs_to :user
has_one :event
end

Related

Active Record Associations: has_and_belongs_to_many, has_many :through or polymorphic association?

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

Rails - Display / Manage many-to-many relationship

I'm a beginner in the wonderful Rails world, but I find some difficulties.
Here's my situation :
I have some Users, Users using Webapps, and appears a join table, "Quota", to track activities of each user on each webapp.
So, in the database table of Quota we find : user_id, webapp_id, quantity : int.
My models :
class Webapp < ActiveRecord::Base
#has_many :webapps_quota, :through => :quota, source: :user
has_and_belongs_to_many :quota
accepts_nested_attributes_for :quota
end
class Webapp < ActiveRecord::Base
#has_many :webapps_quota, :through => :quota, source: :webapp
has_and_belongs_to_many :quota
accepts_nested_attributes_for :quota
end
class Quota < ActiveRecord::Base
belongs_to :user
belongs_to :webapp
accepts_nested_attributes_for :user
accepts_nested_attributes_for :webapp
end
I'm seriously desperate about how I deal with this. How do I show his quota to an user for example?
Thanks for your help.
In order to add attributes in the association table you should use has_many through association:
class User < ActiveRecord::Base
has_many :quotas
has_many :webapps, through: :quotas
end
class Quota < ActiveRecord::Base
belongs_to :user
belongs_to :webapp
end
class Webapp < ActiveRecord::Base
has_many :quotas
has_many :users, through: :quotas
end
Your question: How do I show his quota to an user for example?
user = User.find(1)
user.quotas #display the quotas for that user
user.webapps #display the webapps for that user

How to Model a multi-participant conversation system

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.

Associations, Models, and Controllers for a job application in Rails 4

I am making a job application where the user registers and has a profile, can create companies and withing the companies jobs. To explain a bit easier, a simple LinkedIn.
User has_one Profile (thinking of using the gem Virtus or Cocoon so user can access attribute from Profile and not using accepts_nested_attributes_for)
User has_many Companies
User has_many Applications to many jobs
I somewhat know how the application should be modeled but not completely sure and would appreciate some feedback and help. I will post what I think it should be and hope to get some suggestions. Thanks in advance!
class User < ActiveRecord::Base
has_one :profile, :dependent => :destroy
has_many :applications
has_many :jobs, through: :applications
has_many :companies
end
class Profile < ActiveRecord::Base
belongs_to :user
end
class Company < ActiveRecord::Base
has_many :jobs
end
class Job < ActiveRecord::Base
belongs_to :company
end
class Application < ActiveRecord::Base
belongs_to :user
belongs_to :job
end

Ruby on Rails four-way association tree

The big picture: I am creating an app to track temporal events historically. I am setting it up with four main models: Users, Events, Stories and Images. The idea is that any given user can create an Event, and add Stories and/or Images to his own Event or to any other one. But both Stories and Images are always attached to a certain Event, and any other model belongs to the User who created it (for filtering and editing purposes)
The general structure of the associations would be something like this:
class User < ActiveRecord::Base
has_many :events
has_many :stories
has_many :images
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :stories
has_many :images
end
class Story < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
class Image < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
I am kind of new to Rails and I have little-to-no control over more complex associations as many_to_many, through: or as:
My question here is, is this set of associations optimal, or could it be improved by combining them in a different way?
You're in the right track, but story and image shouldn't belong to user. You're creating a redundancy in there.
class User < ActiveRecord::Base
has_many :events
has_many :stories, :through => :events
has_many :images, :through => :events
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :stories
has_many :images
end
class Story < ActiveRecord::Base
belongs_to :event
end
class Image < ActiveRecord::Base
belongs_to :event
end
This way you can still write user.stories and user.images.
Try to use nested attributes:
http://railscasts.com/episodes/196-nested-model-form-part-1
Sample code:
class User < ActiveRecord::Base
has_many :events
accepts_nested_attributes_for :events
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :stories
has_many :images
accepts_nested_attributes_for :stories, :images
end
class Story < ActiveRecord::Base
belongs_to :event
end
class Image < ActiveRecord::Base
belongs_to :event
end
Nested attributes accepts many level. In this case, there are 3 levels
user
event
story and image.
It like the sample at rails cast with 3 level (survey - question -answer).
Look at the link above and watch the part 2 to see how it work.
Or you can't look at my sample, but it work with 2 levels(subject - task).
Link at here
Login with account: duyet.vn#gmail.com/12341234

Resources