Rails: Create migrations for has_many and has_one - ruby-on-rails

I have Question, Option and Answer models as follows:
class Question < ApplicationRecord
belongs_to :user
has_many :options
has_one :answer
end
class Option < ApplicationRecord
belongs_to :question
has_many :answers
end
class Answer < ApplicationRecord
belongs_to :question
belongs_to :option
end
I have one migration files for Question and Option models like this:
class CreateQuestions < ActiveRecord::Migration[5.2]
def change
create_table :questions do |t|
t.text :body
t.references :user, foreign_key: true
t.timestamps
end
end
end
class CreateOptions < ActiveRecord::Migration[5.2]
def change
create_table :options do |t|
t.references :question, foreign_key: true
t.timestamps
end
end
end
If my understanding is correct, I have a migration here for belongs_to association. My doubt is, are these migration files enough to create has_many associations or do I need to add any extra conditions in migrations files? If yes, please tell me what to add. I referred the following link:
[https://stackoverflow.com/questions/35771847/rails-survey-style-application-show-all-answers-on-option][1]
[1]: Rails survey style application - Show all answers on option but I did not understand whether I need to add extra line for has_many and has_one associations.

Your migrations are correct, because if you think of your models as in database tables, you will never store the 'has_many' option somewhere. That is merely for the human understanding, as well as for ActiveRecord.
So an option in your example belongs to a question, hence we have to store the ID of that question in the record of the answer. In the question migration however, we don't store any information regarding the option, it is enough that the option "knows" which question it belongs to. (And same for user and question).
Only in the model you can then specify - as you did - the 'has_many' options. This will allow you later to call 'question.options` to retrieve all options that belong to a question.

Related

Rails many to many associations and has_many, through:

I created my models a week ago, but I didn't know many things that I know now so it is time to create it from scratch.
What I want to accomplish is to create:
Lab model that can have many offers
Offer model that can have many labs.
#MIGRATION FILES BELOW:
class CreateLabs < ActiveRecord::Migration[5.0]
def change
create_table :labs do |t|
t.string :name
...
t.timestamps
end
end
end
class CreateOffers < ActiveRecord::Migration[5.0]
def change
create_table :offers do |t|
t.string :name
...
t.timestamps
end
end
end
# Join table:
class CreateLabChain < ActiveRecord::Migration[5.0]
def change
create_table :lab_chain do |t|
t.references :lab, foreign_key: true
t.references :offer, foreign_key: true
t.timestamps
end
end
end
And here is how the model files look like:
class Lab < ApplicationRecord
has_many :offers, through: :lab_chain
has_many :lab_chains
end
class Offer < ApplicationRecord
has_many :labs, through: :lab_chain
has_many :lab_chains
end
class LabChain < ApplicationRecord
belongs_to :lab
belongs_to :offer
end
I just want to know if I wrote it all correctly as I am not sure about all those tutorials I have watched and read.
Bonus question is what if I want my Offer to have many sections, and section to have many offer_items? Should I just add:
to Offer:
has_many :sections
has_many :offer_items, through: :section
and then to Section:
has_many :offer_items
belongs_to :offer
and the to OfferItem:
belongs_to :section
?
As I mentioned before, I volunteered as a guy that would make a website for our school project as I was the only one that had something to do with code (different language). It is harder than I thought.
EDIT
How would I also correctly add an self join in Section, so a section can have a subsection and so on?
Self joins addded to Section model
has_many :child_sections, class_name: "Section", foreign_key: "section_id"
belongs_to :parent_section, class_name: "Section"
Added to migration file
t.references :parent_section, foreign_key: "section_id"
That does look like a correct many to many association. You second also looks correct.
As an aside, it helps to draw a diagram of any database with more than 3 tables and if you plan on doing this as a job, it's well worth it to really grasp the whole table relationships fully as it's core to writing good model code.

Understanding Rails Model Associations

I'm relatively new to Ruby on Rails and I'm trying to understand the way how active record associations work. So far, I thought I figured it out, but not sure anymore.
Anyway, I'm building my very own CMS and apart from all, I'll focus on my main problem. I'm having a table pages and pictures:
class CreatePages < ActiveRecord::Migration
def change
create_table :pages do |t|
t.string :name
t.integer :headline_image_id
t.timestamps
end
create_table :pictures do |t|
t.string :name
t.string :description
t.string :image
t.timestamps
end
end
end
With this I have my models:
class Page < ActiveRecord::Base
validates :name, presence: true
validates :headline_image_id, presence: true
belongs_to :headline_image, class_name: Picture, foreign_key: :headline_image_id
end
class Picture < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
And that's it. Now after I create a picture and a page which has the id of a picture in the headline_image_id attribute, I can fetch that headline_image with #target_page.headline_image. Perfect, but the thing that is bothering me is the readability of the code. Wouldn't it make much more sense if I associated the two models in the Page model like this:
class Page < ActiveRecord::Base
validates :name, presence: true
validates :headline_image_id, presence: true
has_one :headline_image, class_name: Picture, foreign_key: :headline_image_id
end
If I do it like this and run #target_page.headline_image I get a SQL Constraint exception that tells me there is no headline_image_id in the pictures table.
I read all the Active Record Association tutorial on Ruby on Rails Guides and watched all the codeschool Rails courses, and I was pretty sure that everything was going to work with a has_one association...but it didn't.
Can someone please explain?
Thanks!
Rails Guides provides an explanation as to why you're experiencing the problem. Essentially, when you declare a belongs_to relationship, the foreign key appears on the table for the class declaring it. When you declare a has_one relationship, the foreign key is on the table for the class in the declaration.
Example
In this scenario, the pictures table would require a page_id foreign key.
class Page < ActiveRecord::Base
has_one :picture
end
class Picture < ActiveRecord::Base
belongs_to :page
end
In this scenario, the pages table would require a picture_id foreign key.
class Page < ActiveRecord::Base
belongs_to :picture
end
class Picture < ActiveRecord::Base
has_one :page
end
If you wanted to use a has_one association, just remove the headline_image_id column from your pages table and add a page_id column to your pictures table. You can do this in one migration. After you run the migration, change your model definitions as per my above example. Hope this helps.

A Ruby on Rails has_many relationship.

I'm new to RoR and working on my first project. The basic concept behind the idea is to connect "Users" that have chosen a set a "Skills" with other Users that that have submitted a "Help Request" that deals specifically with those chosen skills. An app that connects Skilled Users with Users that need help if you will. My question has to do with the relationship between the Users, Skills, and Help_Request Models. It feels like a "has_many :through association" or maybe "polymorphic association" might be in order for this kind of three way relationship? Really not sure?
Any thoughts or suggestions would be greatly appreciated.
A polymorphic association is when a model should belong to another model. Let's say when you a comment model. You can comment on a post and a comment itself. That's when you would use a polymorphic.
In your case a simple has_many through would do.
It should look like this
class User < ActiveRecord::Base
has_many :skills
has_many :help_requests, through: :skills
end
class Skill < ActiveRecord::Base
belongs_to :user
belongs_to :helpRequest
end
class HelpRequest < ActiveRecord::Base
has_many :skills
has_many :users, through :skills
end
For more information the docs
I'm afraid ShivamD's answer will not suffice. That would require duplicate Skills, and queries the relevant User.help_requests via relationship, where instead you need an intersection.
Not just that, Users who create HelpRequests will already have a has_many relationship. That makes sense.
I won't include schema for the HABTM I'm about to suggest (see here), but I will cover the models. Essentially what you want:
skill = Skill.create(name: "My Skill")
user.skills << skill
help_request.skills << skill
user.matched_help_requests
#> [help_request]
Which can be achieved as follows:
class User
has_and_belongs_to_many :skills
def matched_help_requests
HelpRequest.joins(:skills).where("skills.id IN(?)", skills.pluck(:id))
end
end
class HelpRequest
has_and_belongs_to_many :skills
end
class Skill
has_and_belongs_to_many :users
has_and_belongs_to_many :help_requests
end
EDIT: here's the schmea for the HABTM:
rails g migration add_skills_join_tables
within migration
def change
create_table :skills_users, id: false do |t|
t.references :skill
t.references :user
end
create_table :help_requests_skills, id: false do |t|
t.references :skill
t.references :help_request
end
add_index :skills_users, [:skill_id, :user_id]
add_index :help_request_skills, [:skill_id, :help_request_id]
end
One hay is to create a has_and_belongs_to_manyrelation between the Users and Helprequests and Skills, so you end up with this:
class User < ActiveRecord::Base
has_and_belongs_to_many :skills
end
class Help_request < ActiveRecord::Base
has_and_belongs_to_many :skills
end
class Skills < ActiveRecord::Base
has_and_belongs_to_many :users
has_and_belongs_to_many :help_requests
end
Then you need to create the tables
rails g migration add_skills_users_table
rails g migration add_help_requests_skills_table
In the end run rake db:migrate
You can then search for it using User.first.skills

referencing two models to each other

i'm going through one of ror beginners books, and it has this example on references:
class Article < ActiveRecord::Base
attr_accessible :body, :excerpt, :location, :published_at, :publisher, :title
validates :title, :presence => true
validates :body, :presence => true
belongs_to :user
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :articles
end
so these two models are meant to be connected by habtm in both ways, just like in the code above. but, the book also tells me i should provide such a migration:
class CreateArticlesCategories < ActiveRecord::Migration
def up
create_table :articles_categories, :id => false do |t|
t.integer :article
t.integer :category
end
end
def down
drop_table :articles_categories
end
end
My question: why? why do i need to create this migration and not a model articles_categories?
tl;dr; You need the extra model when you're using a has_many through, you don't need it for the habtm association
The has_and_belongs_to_many association is meant to be used when you don't really care about the table in the middle (here it's articles_categories). What I mean by "don't" really care is that, there are no extra data needed in this table. It's only here to tell you which categories are related to a given article, and which articles are related to a given category.
For that purpose the has_and_belongs_to_many association is great cause you don't have to create the model, it only needs the join table.
If somehow you need some extra data in that table, like tags, dates, status, or anything, then it would be really handy to have a dedicated model, so you could explicitly manipulate it.
For those cases, you should use the has_many :through association
If you need more information, I suggest you read the rails guide about association, it's a good start. And of course if my explanation is not clear enough, please tell me, and I'll add more details.

Configure my model so that a field can reference many different types of classes

Let's say that I have a Company model and a Product model, both of which have an UserUploadedImage associated with them. I want to create my UserUploadedImage in a way such that I can write image.parent and that will reference either the Product or the Company, whichever is appropriate in that case.
I realize I can store a second column in UserUploadedImage with either Product or Company and have a conditional to look up the appropriate value. I am, however, not sure where the optimal place to put this code is, or whether there is a cleaner way of achieving my goal. Thanks!
What you need to look at is Polymorphic Associations
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
Polymorphic Associations
A slightly more advanced twist on associations is the polymorphic association. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
You can think of a polymorphic belongs_to declaration as setting up an interface that any other model can use. From an instance of the Employee model, you can retrieve a collection of pictures: #employee.pictures.
Similarly, you can retrieve #product.pictures.
If you have an instance of the Picture model, you can get to its parent via #picture.imageable. To make this work, you need to declare both a foreign key column and a type column in the model that declares the polymorphic interface:
class CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string :name
t.integer :imageable_id
t.string :imageable_type
t.timestamps
end
end
end
This migration can be simplified by using the t.references form:
class CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string :name
t.references :imageable, :polymorphic => true
t.timestamps
end
end
end

Resources