I'm a rails beginner and I'm having a little trouble testing model associations in the Rails Console. I know this is a simple fix, however, I'm not sure that I've created the appropriate models, or generated the right migrations, so I will include this information in this question.
I've read rails documentations (http://guides.rubyonrails.org/active_record_basics.html , http://api.rubyonrails.org/), I know the answer is in there, but i'm afraid my lack of experience is preventing me from totally maximizing the available documentation.
I need to be able to create an article that has_many :categories, through: :article_categories in the rails console
Here is the model for article , article_categories, and category
class Article < ActiveRecord::Base
belongs_to :user
has_many :article_categories
has_many :categories, through: :article_categories
validates :title, presence: true
validates :content, presence: true
validates :categories, presence: true
end
class ArticleCategory < ActiveRecord::Base
belongs_to :article
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :article_categories
has_many :articles, through: :article_categories
validates :names, presence: true
end
And here are the main migrations generated
Class CreateArticles < ActiveRecord::Migration
def change
create_table :articles do |t|
t.string :title
t.text :context
end
end
end
class CreateArticleCategories < ActiveRecord::Migration
def change
create_table :article_categories do |t|
t.belongs_to :article
t.belongs_to :category
t.timestamps
end
end
end
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.timestamps
end
end
end
So, again, the question is if all models and migrations are appropriately generated. How would I go about testing it in the rails console by adding an Article that has a Categorythrough the ArticleCategories table.
As of right new I've tested adding a new Category which works and adding an Article Category, which also works, but I do not know how to add the associations when I create an Article.
I've used
Article.errors.full_messages
which clearly tells me that I need to add categories before saving the article, but again, I don't know how to do that.
Thanks in advance!
You can use .build
#article = Article.new(:title => "foo")
#category = #article.categories.build(:name => "bar")
#article.save
##article & #category should now have been created
Or make them seperately and join them afterwards.
#article = Article.create(:title => "foo")
#category = Category.create(:name => "bar")
#article.categories << #category
#article = Article.create(:title => "foo")
#article = Article.create(:title => "foo")
#article.categories << #category
Related
I have this migration and model for order and order_detail with cocoon gem.
class CreateOrders < ActiveRecord::Migration[5.0]
def change
create_table :orders do |t|
t.integer :total_price
t.timestamps
end
end
end
class CreateOrderDetails < ActiveRecord::Migration[5.0]
def change
create_table :order_details do |t|
t.integer :subtotal_price
t.integer :unit_price
t.integer :quantity
t.references :order, foreign_key: true
t.timestamps
end
end
end
class Order < ApplicationRecord
has_many :order_details, inverse_of: :order, dependent: :destroy
before_validation :calculate_order_price
accepts_nested_attributes_for :order_details, :reject_if => :all_blank, :allow_destroy => true
def calculate_order_price
order_details.each(&:calculate_order_detail_price)
self.total_price = order_details.map(&:subtotal_price).sum
end
end
class OrderDetail < ApplicationRecord
belongs_to :order
def calculate_order_detail_price
self.subtotal_price = unit_price * quantity
end
end
When I save the record after to add or edit the nested field, it works well. But if I edit to delate nested field, calculate_order_price doesn't work.
If somebody knows about this, please advise me.
There is an option :touch which will make sure upon update the parent sets the updated_at (or other fields) but it will not run the validations. There is however also an option :validate (but not entirely sure it will be called upon destroy):
belongs_to :order, validate: true
Otherwise, if those not work, you could do something like
class OrderDetail < ApplicationRecord
belongs_to :order
after_destroy :trigger_parent_validation
def trigger_parent_validation
if order.present?
order.validate
end
end
end
I'm a newbie and this issue is really frustrating but I have no doubt anyone with experience will see the problem pretty quick.
I am getting an undefined method `build_address' from my CompaniesController. I have a polymorphic has_one relationship to PostalAddress from Company. As part of a sign-up form I am trying to create new company and associated address objects in CompaniesController new method. I am using the correct syntax for build on a has_one.
Models
class Company < ActiveRecord::Base
has_one :postaladdress, as: :address, dependent: :destroy
accepts_nested_attributes_for :postaladdress
end
class PostalAddress < ActiveRecord::Base
belongs_to :address, polymorphic: true
end
Controller
class CompaniesController < ApplicationController
def new
#company = Company.new
#address = #company.build_address
end
end
Migrations
class CreateCompanies < ActiveRecord::Migration
def change
create_table :companies do |t|
t.string :name
t.string :subdomain
t.timestamps
end
end
end
class CreatePostalAddresses < ActiveRecord::Migration
def change
create_table :postal_addresses do |t|
t.string :addressline1
t.string :addressline2
t.string :addressline3
t.string :town
t.string :county
t.string :postcode
t.string :country
t.references :address, polymorphic: true;
t.timestamps
end
end
end
Nested Resources in routes.rb
resources :companies do
resources :postaladdresses :except => :destroy
end
As you have a has_one association setup between Company and PostalAddress, you would need to use
#address = #company.build_postal_address
UPDATE
Association in Company should look like:
has_one :postal_address, as: :address, dependent: :destroy
Use postal_address and not postaladdress as your model name is PostalAddress and not Postaladdress
NOTE:
Just for reference, if you had has_many association, then it would have been as:
#address = #company.postal_address.build
For additional details, read about Auto-generated methods for Associations
I'm trying to create a web application to organize a user's TV interests, to do this, I need to store data of three types: Shows, Seasons, and Episodes.
I would like to query my data like this: Show.find(1).season(2).episode.each. This should return each episode of the second season of the show with the id 1. How can I set my model up to a achieve this?
I've tried having values of season_id and show_id on the episodes, but its unable to find the episodes belonging to each season.
Define relationship in mode,
Show
has_many :seasons
Season
has_many :episodes
belongs_to :show
Episode
belongs_to :season
Then you can call like this,
Show.find(1).seasons.first.episodes.each {}
Maybe it's a good idea to read through the guides. Assuming that your entity relationships looking like this:
You can implement this with activerecord easily. The models would look like this:
require 'active_record'
class Show < ActiveRecord::Base
has_many :seasons
end
class Season < ActiveRecord::Base
belongs_to :show
has_many :episodes
end
class Episode < ActiveRecord::Base
belongs_to :season
end
Your migrations could look like:
require 'active_record'
class CreateShows < ActiveRecord::Migration
def change
create_table :shows do |t|
t.timestamps
end
end
end
class CreateSeasons < ActiveRecord::Migration
def change
create_table :seasons do |t|
t.references :show, :null => false
t.timestamps
end
end
end
class CreateEpisodes < ActiveRecord::Migration
def change
create_table :episodes do |t|
t.references :season, :null => false
t.timestamps
end
end
end
Put some data into your database and query them with:
Show.find(1).seasons.first.episodes.each{ |e| puts e.title }
The answers above are great; I'd take it a step further and use has_many's :through option in the Show model and has_one :through on the Episode model:
# Show
has_many :seasons
has_many :episodes, through: :seasons
# Season
belongs_to :show
has_many :episodes
# Episode
belongs_to :season
has_one :show, through: :season
This lets you make calls like this:
Show.first.episodes
Episode.first.show
... and will also allow you to write some query-minimizing scopes, and write delegate methods that simplifying finding related information.
# Episode
delegate :name, to: :show, prefix: :show
Episode.first.show_name # => Episode.first.show.name
I have a scenario where the models look like
create_table :users do |t|
t.string :name
t.timestamps
end
create_table :blogs do |t|
t.string :url
t.string :title
t.text :description
t.timestamps
end
create_table :posts do |t|
t.integer :user_id, :null => false
t.integer :blog_id, :null => false
t.text :post_text
end
class Blog < ActiveRecord::Base
has_many :users, :through =>:posts
has_many :posts, :dependent=>true
end
class User < ActiveRecord::Base
has_many :blogs
has_many :posts, :through=>:blogs
end
class Post < ActiveRecord::Base
belongs_to :blog
belongs_to :user
end
The question I have is:
1. When a user is created, I would like to create a blog for him automatically.
#user = User.find_or_create_by_name(user_name)
How do I go about creating a blog?
#blog = Blog.find_or_create_by_user_id(#user)
I am getting the following error:
undefined method `find_or_create_by_user_id' for #<Class:0x1044735b0>
#blogs = #user.blogs
gives me:
Mysql::Error: Unknown column 'blogs.user_id' in 'where clause': SELECT * FROM `blogs` WHERE (`blogs`.user_id=1234)
I know Blogs table does not have user_id column.
But isn't the join supposed to take care of it?
What am I doing wrong here?
Thanks for your help
To use the Post model as the association table, the User model needs to be tweaked to properly demonstrate the association. Once done, you could use after_create to create a new blog for a newly created user.
class User < ActiveRecord::Base
has_many :posts
has_many :blogs, :through=>:posts
after_create :add_blog
private
def add_blog
blogs << Blog.new
end
end
EDIT:
The best I know how to handle it is to explain what I "think" the relationships are attempting to accomplish then you tell me where I'm off and we go from there.
1) A User can "own" many blogs
2) A blog can have many posts
3) A post belongs to a single user and to a single blog
4) a blog can only have one "owner" (user)
5) Blogs can be "owned" by many users thereby giving them permission to post.
If 1-4 are true, and 5 false... that isn't a "has_many :through" scenario or many-to-many relationship, just one-to-many relationships.
Accordingly, posts should not be used as an association table. There isn't an association table needed.
add t.integer :user_id, :null => false to the blogs table
class Blog < ActiveRecord::Base
belongs_to :users,
has_many :posts, :dependent=>:destroy # rec'd error in RoR3... replaced true with :destroy
end
class User < ActiveRecord::Base
has_many :blogs, :dependent=>:destroy
has_many :posts
after_create :add_blog
private
def add_blog
blogs << Blog.new
end
end
class Post < ActiveRecord::Base
belongs_to :blog
belongs_to :user
end
If 5 is true, this would be a true many-to-many... but I don't think that's what you're attempting to do.
I've been working on my Rails app and I am stuck with some associations that I can't get my head around.
Here are my models:
User Model
class User < ActiveRecord::Base
has_many :events, :dependent => :destroy
end
Event Model
class Event < ActiveRecord::Base
belongs_to :user
has_many :items, :dependent => :destroy
end
Item Model
class Item < ActiveRecord::Base
belongs_to :event
end
When I head into the rails console and do something like this:
> User.last.events.last.items
I get an error like this:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: items.event_id: SELECT "items".* FROM "items" WHERE ("items".event_id = 1)
I have set my migrations like this:
class CreateItems < ActiveRecord::Migration
def self.up
create_table :items do |t|
t.string :description
t.string :name
t.integer :event_id
t.timestamps
end
add_index :items, :event_id
end
def self.down
drop_table :items
end
end
Is it something to do with my associations and the way that I have laid it out?
Or is the the depth of the associations?
I hope that I've provided enough information.
Thanks everyone!
I'd suggest that you double check that you've run your migration (rake db:migrate).
It shouldn't matter, but you might also try "t.references :event" instead of "t.integer :event_id".