2 votes

Comment permettre aux utilisateurs de ne voir les liens d'édition et de suppression que si l'article est le leur ?

Mes utilisateurs sont configurés via Devise. Je peux également utiliser CanCanCan.

J'ai mis en place un modèle d'articles et tout utilisateur peut créer des articles. Ils peuvent uniquement supprimer et modifier leurs propres créations d'articles. Sur l'index, ils peuvent voir tous les articles qui ont été créés par tous les utilisateurs. Il existe actuellement une option permettant de visualiser, de modifier et de supprimer. Je souhaite que cette option ne soit visible que pour les articles appartenant à l'utilisateur. Je veux que toutes les autres lignes d'article soient vides. (Sauf pour l'administrateur bien sûr). Les utilisateurs peuvent voir les articles sur views/articles/index.html.erb

<table>
  <tr>
    <th>Title</th>
    <th>Description</th>
  </tr>

  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.description %></td>
      <td><%= link_to 'View', article_path(article) %></td>
      <td><%= link_to 'Edit', edit_article_path(article) %></td>
      <td><%= link_to 'Delete', article_path(article),
              method: :delete,
              data: { confirm: 'Are you sure?' } %></td>
    </tr>
  <% end %>
</table>

Comment puis-je permettre aux utilisateurs de ne voir les boutons Modifier et Supprimer que sur les articles dont ils sont propriétaires ?

J'ai essayé mais ça ne marche pas :

<table>
  <tr>
    <th>Title</th>
    <th>Description</th>
  </tr>

  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.description %></td>
      <td><%= link_to 'View', article_path(article) %></td>
      <% if user_signed_in? && current_user.articles.exists?(@article.id) %>
      <td><%= link_to 'Edit', edit_article_path(article) %></td>
      <td><%= link_to 'Delete', article_path(article),
              method: :delete,
              data: { confirm: 'Are you sure?' } %></td>
      <% end %>
    </tr>
  <% end %>
</table>

J'ai aussi essayé :

      <% if current_user && current_user.articles.exists?(@article.id) %>

Voici à quoi ressemble le contrôleur de mes articles : (Je sais que je dois l'améliorer).

def create
  @article = current_user.articles.build(article_params)

  if @article.save
    redirect_to @article
  else
    render 'new'
  end
end

def update
  @article = Article.find(params[:id])
  if user_signed_in? && current_user.articles.exists?(@article.id)
    if @article.update(article_params)
      redirect_to @article
    else
     render 'edit'
    end
  elsif current_user && current_user.admin_role?
    if @article.update(article_params)
      redirect_to @article
    else
     render 'edit'
    end
  else
    redirect_to @article
  end
end

def destroy
  @article = Article.find(params[:id])
  if user_signed_in? && current_user.articles.exists?(@article.id)
    @article.destroy
    redirect_to articles_path
  elsif current_user && current_user.admin_role?
    @article.destroy
    redirect_to articles_path
  else
    redirect_to articles_path
  end
end

1voto

Sebastian Palma Points 15219

Comme vous avez accès à la current_user fourni par Devise, vous pouvez alors le comparer avec le propriétaire de l'article. Cela peut être dans la vue, pour rendre les liens appropriés pour effectuer les actions :

<% @articles.each do |article| %>
  <tr>
    <td><%= article.title %></td>
    <td><%= article.description %></td>
    <td><%= link_to 'View', article_path(article) %></td>
    <% if current_user == article.user %>
      <td><%= link_to 'Edit', edit_article_path(article) %></td>
      <td><%= link_to 'Delete', article_path(article),
              method: :delete,
              data: { confirm: 'Are you sure?' } %></td>
    <% end %>
  </tr>
<% end %>

Vous pouvez déplacer cette vérification vers une aide, dans l'ApplicationHelper, pour qu'elle soit disponible dans la plupart de vos vues, par exemple :

module ApplicationHelper
  def owner?(object)
    current_user == object.user 
  end
end

Vous passez l'objet, et cela renvoie true ou false selon que l'utilisateur actuel est égal à l'objet object utilisateur. La vue ne change que pour :

<% if owner?(article) %>

Si vous souhaitez déplacer cette vérification vers le contrôleur, ou si vous souhaitez l'utiliser dans les deux cas, vous pouvez alors effectuer la même vérification dans le contrôleur. Comme le owner? n'est pas disponible dans le contrôleur, vous pouvez simplement rediriger vers l'arrière au cas où l'utilisateur actuel n'est pas le propriétaire de l'article, comme suit :

def edit
  unless current_user == @article.user
    redirect_back fallback_location: root_path, notice: 'User is not owner'
  end
end

Si vous voulez déplacer cette partie vers un before afin de pouvoir l'utiliser dans la fonction edit y destroy vous pouvez alors l'ajouter en tant que méthode privée, et avoir accès à la méthode @article vous pouvez faire une telle comparaison, ce serait :

private

def owner?
  unless current_user == @article.user
    redirect_back fallback_location: root_path, notice: 'User is not owner'
  end
end

De cette façon, il suffit de l'ajouter comme une before_action le rappel :

before_action :owner?, only: %i[edit destroy]

Très probablement avant celle qui définit la variable @article.

Notez l'utilisation de redirect_back dans Rails 5, les versions précédentes pouvaient utiliser redirect_to :back .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X