如果文章是自己的,如何让用户只看到编辑和删除链接?

时间:2017-10-08 16:54:59

标签: ruby-on-rails devise cancan

我的用户是通过Devise设置的。我也可以使用CanCanCan。

我设置了一个文章模型,任何用户都可以创建文章。他们只能删除和编辑自己的文章创作。在索引上,他们可以查看所有用户创建的所有文章。目前有一个查看,编辑和删除选项。我只希望在用户拥有的文章上看到该选项。我希望所有其他文章行都是空白的。 (当然除了管理员。) 用户可以查看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>

如何让用户只能看到他们拥有的帖子上的“编辑”和“删除”按钮?

我尝试了这个,但它不起作用:

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

我也试过了:

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

这是我的文章控制器的样子:(我知道我需要让它看起来更好。)

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

1 个答案:

答案 0 :(得分:1)

由于您可以访问Devise提供的current_user帮助程序,因此您可以将其与文章所有者进行比较。这可以在视图中,以呈现正确的链接来执行操作:

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

您可以将此验证移至帮助器,在ApplicationHelper中可在大多数视图中使用,例如:

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

您传递了该对象,并返回true或false,具体取决于当前用户是否等于object用户。视图仅更改为:

<% if owner?(article) %>

如果要将此验证移至控制器,或者如果要在两种情况下都使用它,则可以在控制器中执行相同的验证。由于owner?辅助方法在控制器中不可用,您可以重新定向,以防current_user不是文章的所有者,如:

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

如果您想将此部分移至before回调,以便能够在editdestroy方法中使用它,那么您可以将其添加为私有方法,并且可以访问@article你可以进行这样的比较,它是:

private

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

这样您只需将其添加为before_action回调:

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

最有可能在定义@article变量之前。

请注意在Rails 5中使用redirect_back,以前的版本可能会使用redirect_to :back