Hello friends i have this error I've been facing yesterday on my Rails App. I get undefined method `articles' for nil:NilClass when i tried to display related articles on my article show page .
Here is my app codes
tag.rb
class Tag < ApplicationRecord
has_many :taggings
has_many :articles, through: :taggings
def to_s
name
end
end
tagging.rb
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :article
end
articles_controller
class ArticlesController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
before_action :owned_article, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
@articles = Article.all.order("created_at desc")
end
def show
end
def new
@article = current_user.articles.build
end
def create
@article = current_user.articles.build(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def edit
end
def update
if @article.update(article_params)
redirect_to @article, notice: "Your article was successfully updated!"
else
render 'edit'
end
end
def destroy
@article.destroy
redirect_to articles_path
end
private
def find_article
@article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:title, :content, :image, :tag_list)
end
def owned_article
unless current_user == @article.user
flash[:alert] = "That article does not belong to you!"
redirect_to root_path
end
end
end
articles show.html.erb
<div class="container">
<div class="row text-white text-center">
<div class="col-md-10 col-lg-10 ml-sm-auto mr-sm-auto article-show-col">
<br>
<h1><%= @article.title %></h1>
<p class="text-muted">Posted on: <%= @article.created_at.strftime('%-b %-d, %Y') %></p>
<p>
Tags:
<% @article.tags.each do |tag| %>
<%= link_to tag.name, tag_path(tag) %>
<% end %>
</p>
<!-- <br> -->
<div class="article-show-image">
<%= image_tag @article.image.url(:wide) %>
</div>
<!-- <br> -->
<p><%= @article.content.html_safe %></p>
<hr class="index-hr">
<h5>Broadcast this article</h5>
<%= social_share_button_tag("Hey! Checkout this new article from TWM!") %>
<hr class="index-hr">
**<h5>Related Articles</h5>
<% @tag.articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>**
<div class="btn-group">
<%= link_to "Back", articles_path, class: "btn-custom btn-sm" %>
<% if user_signed_in? %>
<% if @article.user_id == current_user.id %>
<%= link_to "Delete", article_path(@article), method: :delete, data: { confirm: "Are you sure you want to delete this article?" }, class: "btn-custom btn-sm" %>
<%= link_to "Edit", edit_article_path, class: "btn-custom btn-sm" %>
<% end %>
<% end %>
</div>
</div>
</div>
tags controller
class TagsController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
def index
@tags = Tag.all.order("created_at desc")
end
def show
end
def destroy
@tag.destroy
redirect_to tags_path
end
private
def find_article
@tag = Tag.find(params[:id])
end
end
show view for tags
<div class="container text-white text-center">
<h1>Articles Tagged with <%= @tag.name %></h1>
<ul>
<% @tag.articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>
</ul>
Thank You!
Here is a longer answer that offers a solution to your problem. The issue is that you want to get all articles
that share a tag
with the article
you are showing, while presumably not showing the current article in the list of related articles. I would accomplish this by adding a related_articles
method to your Article
model and calling it in your view.
Add the following method to app/models/article.rb
:
def related_articles
Article.joins(:tags).where(tags: { id: self.tags.pluck(:id) }).where.not(id: self.id)
end
The above query should return all of the articles that have a matching tag while excluding itself.
You can now replace the related articles section in your view with:
**<h5>Related Articles</h5>
<% @article.related_articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>**
One final note that is not strictly related to your problem, but worth mentioning. By iterating over @article.tags
, your view is creating an N+1 query. These are very inefficient. The good news, is that this can be fixed with eager loading by simply, changing the find_articles
method in your articles_controller
as follows:
def find_article
@article = Article.includes(:tags).find(params[:id])
end
There may be a more efficient way to write the related_articles
query, but this should work.
EDIT:
Another way of writing the related_articles
query follows. This will yield the same results. It moves more of the processing to the database and results in fewer calls to the database.
def related_articles
Article.distinct.joins(tags: :articles).where.not(id: self.id)
end
您的 ArticlesController 在显示视图中使用时不会实例化 @tag 变量。
In your show.html.erb
, you're trying to do:
<div class="container">
<div class="row text-white text-center">
<div class="col-md-10 col-lg-10 ml-sm-auto mr-sm-auto article-show-col">
...
<% @tag.articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>**
...
</div>
</div>
</div>
But, hey, check it out! No @tag
in your show
action:
class ArticlesController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
before_action :owned_article, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
...
def show
#look! no @tag
end
...
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.