Best way to create an association in Rails - ruby-on-rails

I would like my User to be associated with specific Email's, when they receive them.
In this way, I can look up an array of what emails they have received.
Originally, I was thinking of just creating a string field for the User table, and adding the unique ID to the array..
User.find(x).received_emails << Email.find(x).id
But there may be a better way to do this with associating models.
Recommendations?

You should check this link out:
Rails association guide
It sounds like you're talking about a one to many sort of thing. If you use the association mechanism you'll get all the behavior you want, basically for free.

class Email < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :received_emails, :class_name => 'Email'
end
User.find(x).received_emails << Email.find(y)
This approach would require adding a user_id column to the Email table.
You probably want to change this to a many-to-many association by adding a join table such as user_emails with a UserEmail model. That table would have user_id and email_id columns.

Related

setting up a belongs_to relation when the foreign key is stored in metadata

In a Rails 4 application, I have an STI model that stores metadata in a jsonb column.
Base Class:
class Post < ActiveRecord::Base
...
end
Subclass:
class JobPost < Post
# has a jsonb column for metadata
end
One of the data attributes in the metadata column of a JobPost is a foreign_key reference to another table (company_id). I'd like to add a belongs_to :company reference in the JobPost model. It seems like this should be possible by doing something like
class JobPost < Post
belongs_to :company do
Company.find_by_id self.metadata['company_id']
end
end
but that doesn't appear to work. Help?
Note: I am not necessarily intent on using belongs_to rather than writing needed methods like def company by hand, but I do need a way to eager load companies when listing job posts. If there's a way to do that eager loading without a belongs_to relation I'm all ears.
Update1
I have also tried the following, which doesn't appear to work either:
class JobPost < Post
belongs_to :company, foreign_key: "(posts.metadata->>'company_id')::integer".to_sym
end
Update2
To be more clear about my intentions and need:
1) A JobPost belongs_to a Company, but a Post (and other subclasses of Post) does not. I'd prefer not to jankily add the company_id column to the posts table when it won't be used by the other subclasses.
2) A JobPost could justify having it's own table (perhaps the relationship with a Company is enough to justify it). There are reasons why this wouldn't be ideal, but if that's the only answer I'm open to it. I'd, however, like a more definitive "what you're trying to do can't be done" response before going down this road, though.
The primary question is whether you can customize belongs_to so that it uses the metadata column rather than expecting the foreign key to be a column in the table.
The secondary question is whether you can eager load companies alongside job posts without having that belongs_to relation set up.
EDIT
UPD 2
You need to add "company_id" column to the base class of your STI table. If JobPost inherits from Post, and it should have "company_id" then add the "company_id" column to Post (base table).
Remember STI stands for "Single Table Inheritance" so there is only one table on database schema level. Imagine a column of a Post table, where few data records are the foreign key entries for Companies with company_id and what about the other records of this column with non JobPost subclass types, are they null/empty? Hence the relationship is defined with parent STI table and subclass inherits these relations. Additional type column in STI defines the subclass type.
Check here
You may need to dig further on Polymorphic classes instead of STI if both JobPost and Post have relationship with Company, else create two separate model, as they tend do have some unique relationships and column fields.
UPD
Based on updated ask
app/model/company.rb
class Company < ActiveRecord::Base
has_many :posts
delegate :jobposts, to: :posts
end
app/model/post.rb
class Post < ActiveRecord::Base
belongs_to :company
self.inheritance_column = :ptype
scope :job_posts, -> { where(ptype: 'JobPost') }
def self.ptype
%w(JobPost)
end
end
app/models/jobpost.rb
class JobPost < Post; end
Create a company
company = Company.create!(company_params)
Create some posts and add them to the company
company.posts << JobPost.new(jobpost_params)
To fetch jobpost by company relationship
company.job_posts
In case you are storing company_id in jsonb in any which column, just format your jobpost_params hash input accordingly and it should do the deed for you
OLD ASK
To find by primary key
Company.find(id)
In your case, id is self.metadata['company_id']
To find by other keys
Company.find_by(key: value)
Company.find_by_id is no more recommended
Please remove do and end after belongs_to in your model, instead in your controller you can write:
Jobpost.all.each do |x|
# your do
end
regarding foreign key, as rails is convention over configuration, it by default includes company_id reference to Jobpost which you can change in your Company.rb model

Rails Data Modelling: How can I model a has_many relationship that's actually a collection of another model?

To be more specific, I have a User model that has_one Profile, now I'm in the need to add a has_many relationship from User to a new model Contact, but Contact is really a collection of Profiles ("User has_many Profiles" behind the scenes).
How do I correctly model this? Is there a way to avoid creating the new Model Contact altogether?
My concern, and reason to ask this question is having to perform an inefficient query to retrieve the User Contacts collection: user.contacts and then for each Contact I'd have to create a Query to retrieve each Profile, right?
How I can make it so that when I do: user.contacts it retrieves a Collection of Profiles that Doesn't interfere/is independent of the user.profile relationship?
Thanks in advance!
You wouldn't be necessarily need a new Model, but it's easiest (at least, in my opinion) to have one, just not in the way presented above.
Rails aside, you need a join table, like user_profiles, which contains foreign keys for user_id and profile_id. Now, how you make that work is up to you.
Your Contact model here is actually, in a more Rails-y way, a UserProfile model. So your User could look like:
class User
has_many :user_profiles # the join table
has_many :contacts, through: :user_profiles
has_one: profile
end
Here, user.contacts would get you the profiles. You still have that extra model, UserProfile, you just don't use it in practice:
class UserProfile
belongs_to :user
belongs_to :profile
end
Which you can build via:
rails g model UserProfile user:references profile:references
Hope that helps!

Setting up a rails model association

My rails app has a user model that has a HABTM relationship with interests and holidays. Both of these (interests and holidays) only have one attribute that needs to be edited and related to the user. This is setup and working fine.
I need to create a new model called friend_birthday thats contains information regarding the birthdays of the users friends (and their respective interests). This model (friend_birthday) needs to have several attributes ( :name, :gender, :dob, and :interests).
I was thinking on using a has_many/belongs_to for this one. User has many friends_birthdays and friends_birthdays belongs_to a user.
Does this sound right? How could i implement this?
Thanks!!!!
Yes this sounds right, but i think it is better to name model Friend
class Friend
belongs_to :user
#also u can use HABTM for interests,
#but it is better to use rich join table and polymorphic association
has_and_belongs_to_many :interests
end
class User
has_many :friends
end
Ofc if friends are not users)) just RL friends

How to create one master condition for activerecord usage

I have many tables that have the user_id field and I want to filter all the queries to these tables by appending a where clause for this user_id. How would I be able to achieve it in Rails?
Thanks!
I think you're thinking of this backwards. Search those tables through the user object that you have, ensuring that they are already associated in ActiveRecord. So, if you have a table called magazines, you'd use something like this:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :magazines
#app/models/magazine.rb
class Magazine < ActiveRecord::Base
belongs_to :user
Then you can reference all of a user's magazines through an instance of a user:
#user = User.first
#user.magazines.all
That will return all magazines that have a user_id equal to the user's ID.

rails attaching database entry to logged in user

I'm new to rails and am done setting up my login system. However, I want someone to be able to make a new blog post and attach it to their account when logged in. How can I attach a post to their user_id as well as list all their previous posts?
Define a model posts ( should have column name user_id )
model Post < ActiveRecord::Base
belongs_to :user
end
In user Model
model User < ActiveRecord::Base
has_many :posts
end
With the above defined associations user_id will be a foriegn key to User model so you can
get all posts by user something like below
User.find(id).posts
There are quite a few different approaches, but John Nunemaker's user_stamp gem is pretty straightforward and simple to get running.
https://github.com/jnunemaker/user_stamp
Just add a creator_id and updater_id to your table, a single line in your ApplicationController, and it'll do the rest!
You can associate models with each other by following this guide on rails associations. One solution for you might be:
class Post < ActiveRecord::Base
end
class User < ActiveRecord::Base
has_many :posts
end
You just have to make sure that your posts table has a column called user_id. Assuming your user table is called users. this will set up a one to many association between users and posts. From a User instance you will be able to do user.posts and get a list of the associated posts for that user.
The guide is much better at explaining this stuff and it's worth your while to read the whole thing--even the parts you don't need right now.

Resources