How to Reflect in the Database a New Belongs_To and Has_Many Relationship in Ruby on Rails

How to reflect in the database a new belongs_to and has_many relationship in Ruby on Rails

Adding a belongs_to (or any other) relationship to your model only tells active record that models are linked logically. This gives you access to methods like task.user. For this to actually work, the instances must be linked via database fields.

This is the step you're missing: you need to create a migration that will add a column to the Task table indicating which user it belongs to.

rails g migration AddUserIdToTasks user_id:integer

Note AddUserIdToTasks can be whatever name you want. It makes no difference. You can then open db/migrations/add_user_to_tasks and see what it does. Usually self.up will modify the database how you want it and self.down will do the opposite (so, in this case, remove the used_id).

Then to actually execute the SQL commands to alter the database table and schema, run

rake db:migrate

How do I specific belongs_to and has_many relationships when generating new models

When passed as a generator argument belongs_to in is just an alias of references which tells rails to create a column named blog_id which is a foreign key:

# rails generate model Post blog:belongs_to
class CreatePosts < ActiveRecord::Migration[5.0]
def change
create_table :posts do |t|
t.belongs_to :blog, foreign_key: true
t.timestamps
end
end
end

This is the actual database column that defines the relation between two tables.

It also adds the association to the model:

class Post < ApplicationRecord
belongs_to :blog
end

Why does'nt the same work for has_many?

The arguments for the model generators are attributes of the model. blog_id is an actual attribute backed by a database column.

has_many is not an attribute. It's a metaprogramming method which adds a posts method to your Blog instances. You need to add it manually to the model.

If you run rails g model Blog posts:has_many foo:bar Rails will actually create a migration with those attributes:

class CreateBlogs < ActiveRecord::Migration[5.0]
def change
create_table :blogs do |t|
t.has_many :posts
t.bar :foo

t.timestamps
end
end
end

Rails does not type check the arguments. Of course the migration won't actually run:

undefined method `has_many' for #<ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition:0x007fd12d9b8bc8>

If you have already generated the migration just remove the line t.has_many :posts and add has_many :posts to app/models/blog.rb.

Rails Converting a has_many relationship into a has and belongs to many

I suggest you to always use has_many :through instead of HBTM.

To establish this kind of relation you'll need the following set up:

# region.rb
class Region
has_many :facility_regions
has_many :facilities, through: :facility_regions
end

# facility.rb
class Facility
has_many :facility_regions
has_many :regions, through: :facility_regions
end

# facility_region.rb
class FacilityRegion
belongs_to :facility
belongs_to :region
end

Also, of course, you'll need to create a migration:

rails g migration create_facility_regions facility_id:integer region_id:integer
# in this migration create a uniq index:
add_index :facility_regions, %I(facility_id region_id), name: :facility_region
rake db:migrate

UPD

As to migration from one database state to another one.

I think it should not be a problem.

1) Do not delete the relations you had before (leave has_many :facilities and belongs_to :region in models).

2) When new table is created and new associations added to the classes (which I showed) create a new migration:

rails g migration migrate_database_state

3) Write the script, which will create new records in db (to reflect the current state of things):

ActiveRecord::Base.transaction do
Facility.where.not(region_id: nil).find_each do |facility|
next if FacilityRegion.find_by(falicity_id: facility.id, region_id: facility.region_id)
FacilityRegion.create!(facility_id: facility.id, region_id: facility.region_id)
end
end

4) Put this script into last created migration and run it (or in console without migration, effect would be the same).

5) After script is successfully run, create new migration in which you delete region_id from facilities table and remove these associations definitions (has_many :facilities and belongs_to :region) from models.

It must be it. I might have made some typos or so, make sure I did not miss anything and

has_many, belongs_to relation in active record migration rails 4

You could call:

rails g model task user:references

which will generates an user_id column in the tasks table and will modify the task.rb model to add a belongs_to :user relatonship. Please note, you must to put manually the has_many :tasks or has_one :task relationship to the user.rb model.

If you already have the model generated, you could create a migration with the following:

rails g migration AddUserToTask user:belongs_to

which will generate:

class AddUserToTask < ActiveRecord::Migration
def change
add_reference :tasks, :user, index: true
end
end

the only difference with this approach is, the belongs_to :user relationship in the task.rb model won't be created automatically, so you must create it for your own.

Creating a has_and_belongs_to_many relationship in Rails

I would like the teacher to have many users but each user to have only one teacher

You only need has_many / belongs_to...

#app/models/user.rb
class User < ActiveRecord::Base
belongs_to :teacher
end

#app/models/teacher.rb
class Teacher < ActiveRecord::Base
has_many :users
end

You'll need to add a teacher_id column in your users table (the opposite of what you have now):

class UpdateUsers < ActiveRecord::Migration
def change
change_table :users do |t|
t.references :teacher, index: true, foreign_key: true #-> teacher_id
end
end
end

--

The error you have is that you're calling user_id on teacher; it should be teacher_id on user:

@teacher = Teacher.new(name: "Phred Willard",
email: "pwillard@test.com",
phone: "1234567890",
user_ids: [@user.id,
@user2.id,
@user3.id,
@user4.id])

This should associate @teacher with the defined @users you've listed.

You'll also want to look at collection_singular_ids for the has_many association, which is why your test is failing.

Rails: has_many with extra details?

Recipes and Ingredients have a has and belongs to many relationship, but you want to store additional information for link.

Essentially what you are looking for is a rich join model. But, a has_and_belongs_to_many relationship is not flexible enough to store the additional information you require. Instead you will need to use a has_many :through relatinship.

This is how I would set it up.

recipes columns: instructions

class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
has_many :ingredients, :through => :recipe_ingredients
end

recipe_ingredients columns: recipe_id, ingredient_id, quantity

class RecipeIngredients < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
end

ingredient columns: name

class Ingredient < ActiveRecord::Base
has_many :recipe_ingredients
has_many :recipes, :through => :recipe_ingredients
end

This will provide a basic representation of what you're looking to do. You may want to add a validation to RecipeIngredients to ensure that each ingredient is listed once per recipe, and a callback to fold duplicates into one entry.

Has_many through and belongs to in Rails

You're very close, you're just missing the connection. Magazine can see Subscription because Subscription has its magazine_id. User can see Subscription because Subscription has its user_id. Through the Subscription, Magazine and User can see each other. So you want to user through

class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

has_many :magazines, through: :subscriptions
has_many :subscriptions
end

class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :magazine
end

class Magazine < ActiveRecord::Base
belongs_to :user

has_many :subscriptions
has_many :users, through: :subscriptions
end

If this doesn't work, make sure you post your schema.rb/relevant fields from the tables you mentioned.

Using has_many / belongs_to to access info in controller - Ruby on Rails

You shouldn't need to add anything to the controller show action.

In your customer show view you presumably have access to a @customer object. Because of your has_many, that will have a collection @customer.orders. So, in the view, you can do something like

<table>
<thead>
<td>Item</td>
<td>Quantity</td>
<td>Price</td>
<td>Date Placed<td>
</thead>

<% @customer.orders.each do |order| %>
<tr>
<td><%= order.item.name %></td>
<td><%= order.quantity %></td>
<td><%= order.price %></td></tr>
<td><%= order.date_placed %></td>
</tr>
<% end %>

</table>

Obviously I'm making up the possible order fields you'd want to display, but this should give you the idea.

Rails has many and belongs to one

Add a creator_id column to your projects table for the creator relationship, and then add the associations to the models:

class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects

has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end

class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects

belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

Rails Has and Belongs To Many Associations

If you just want to show parents and their children at view you don't need to create new table, just do as below:

In your Parents controller's index action( I am considering that you want to show all the parents with their children so I am using index action ) :

def index
@parents= Parent.all.includes(:children)
end

Then on your index.html.erb view :

<% @parents.each do |parent| %>
<%= parent.name%><br/>
<% parent.children.each do |child| %>
<%= child.name%><br/>
<% end %>
<% end %>

Considering that you have define association between you Parent an Child model



Related Topics



Leave a reply



Submit