2017-10-03 1 views
1

Bonjour mes amis j'ai cette erreur que j'ai été confronté hier sur mon Rails App. Je reçois la méthode undefined `articles 'pour nil: NilClass quand j'ai essayé d'afficher des articles connexes sur ma page show article.undefined la méthode `articles 'pour nil: NilClass quand j'ai essayé d'afficher des articles connexes sur ma page show article

Voici mes codes d'applications

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 

fin

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> 

balises contrôleur

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 vi ew pour les balises

<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> 

Merci!

+0

Publiez votre fichier 'routes.rb' et assurez-vous d'inclure la ligne où votre méthode' show' est définie. Il est possible que 'id' ne soit pas le nom de l'attribut que vous devez extraire de' params'. – anothermh

+0

Dans votre article show.html.erb, vous utilisez *@tag.articles et * * @ tag * n'existe pas. –

Répondre

0

Voici une réponse plus longue qui offre une solution à votre problème. Le problème est que vous voulez obtenir tous les articles qui partagent un tag avec le article que vous montrez, tout en ne montrant probablement pas l'article actuel dans la liste des articles connexes. J'accomplirais cela en ajoutant une méthode related_articles à votre modèle Article et en l'appelant dans votre vue.

Ajouter la méthode suivante pour app/models/article.rb:

def related_articles 
    Article.joins(:tags).where(tags: { id: self.tags.pluck(:id) }).where.not(id: self.id) 
end 

La requête ci-dessus doit retourner tous les articles qui ont une étiquette correspondante en s'excluant.

Vous pouvez maintenant remplacer la section des articles connexes à votre avis avec:

**<h5>Related Articles</h5> 
<% @article.related_articles.each do |article| %> 
    <li><%= link_to article.title, article_path(article) %></li> 
<% end %>** 

Une note finale qui est pas strictement lié à votre problème, mais la peine de mentionner. En itérant sur @article.tags, votre vue crée une requête N + 1. Ce sont très inefficaces. Les bonnes nouvelles, est que cela peut être résolu avec eager loading simplement, en changeant la méthode find_articles dans votre articles_controller comme suit:

def find_article 
    @article = Article.includes(:tags).find(params[:id]) 
end 

Il peut y avoir un moyen plus efficace d'écrire la requête related_articles, mais cela devrait fonctionner.

EDIT:

Une autre façon d'écrire la requête related_articles suit. Cela donnera les mêmes résultats. Il déplace plus de traitement vers la base de données et entraîne moins d'appels à la base de données.

def related_articles 
    Article.distinct.joins(tags: :articles).where.not(id: self.id) 
end 
+0

Après avoir défini la méthode related_articles comme vous l'avez dit, j'ai pu réaliser ce que je voulais ... Vous avez sauvé mon stress, je suis reconnaissant. Cependant, quand j'ai changé ma méthode find_article j'ai eu cette erreur "méthode non définie' inclut 'pour # " – Lashe

+0

Bon point. Le 'includes' devrait aller avant le' find'. Je vais mettre à jour la réponse. –

+0

J'ai mis à jour la réponse pour utiliser une requête plus efficace pour 'related_articles' –

0

Votre contrôle ArticlesController n'instancie pas de variable @tag lorsqu'il est utilisé dans la vue d'affichage.

0

Dans votre show.html.erb, vous essayez de le faire:

<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> 

Mais, hey, check it out! Pas @tag dans votre action show:

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 
0

La variable @tag n'est pas défini dans votre ArticlesController, il est donc pas disponible pour articles show.html.erb.

Bien que cette réponse explique le problème, elle n'offre pas de solution. J'ai posté une nouvelle réponse avec une solution.