We've attempted a has_many
, belongs_to relationship
: we've created a class - ArticleCategory
- that belongs to Article
. Articles have many article_categories. ArticleCategory has one attribute - sport:string
We are unable to call Article.last.article_categories
as it returns this error message:
NoMethodError: undefined method
Here is our relevant code:
ArticleCategories Controller
class ArticleCategoriesController < ApplicationController
before_action :set_article_category, only: [:show, :edit, :update, :destroy]
def index
@article_categories = ArticleCategory.all
respond_with(@article_categories)
end
def show
respond_with(@article_category)
end
def new
@article_category = ArticleCategory.new
respond_with(@article_category)
end
def edit
end
def create
@article = Article.find(params[:article_id])
@article_category = @article.article_categories.build(article_category_params)
# @article_category = ArticleCategory.new(article_category_params)
@article_category.save
respond_with(@article_category)
end
def update
@article_category.update(article_category_params)
respond_with(@article_category)
end
def destroy
@article_category.destroy
respond_with(@article_category)
end
private
def set_article_category
@article_category = ArticleCategory.find(params[:id])
end
def article_category_params
params.require(:article_category).permit(:sport)
end
end
ArticleCategories Model
class ArticleCategory < ActiveRecord::Base
belongs_to :article
end
Articles Controller
class ArticlesController < ApplicationController
load_and_authorize_resource
skip_authorize_resource :only => [:index, :show]
def new
@article = Article.new
end
def create
@article = Article.new(article_params)
# authorize! :create, @article
if @article.save
#send email to referral email
all_users = User.all
all_users.each do |user|
ArticleMailer.article_confirmation(user,@article).deliver
end
redirect_to @article
else
render 'new'
end
end
def show
@article = Article.find(params[:id])
end
def index
@articles = Article.all.reverse
end
def edit
@article = Article.find(params[:id])
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :date, :kredit, article_categories_attributes: [:id, :sport])
end
end
Articles Model
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :article_categories, dependent: :destroy
accepts_nested_attributes_for :article_categories, :allow_destroy => true
validates :title, presence: true,
length: { minimum: 5 }
end
We can't figure out why we can't call this method on Article.last
Since my comment helped, I'll add this as an answer so we can close this off
If you had the console open when you made changes to the model, those changes aren't reflected yet until you either exit and re-enter the console, or type reload!
. Either of these will cause the console to reload all of your classes. In short, your classes remain in the state they were in when you first loaded the console, so its something to keep in mind when you're developing and playing around in the console simultaneously.
Regarding your question from the comments:
When we call with an instance of the article - @article.article_categories - we get this <ArticleCategory::ActiveRecord_Associations_CollectionProxy:0x007fc46acc5db8>
That's correct, you get back an association object. Most of the time you don't need to worry about this, as invoking some array methods such as .each
and such will give you the concrete objects.
The collection proxy object, however, lets you perform other active record method calls to further filter the article_categories
list if you like. You can do stuff like this, for example:
article.last.article_categories.where(sport: "curling")
and the article_categories
list will be limited to those that match the .where
clause filter. You can verify this in the console or rails log by looking at the generated SQL query.
Hope that helps.