【问题标题】:How can I make it so only users who are admins can post articles?我怎样才能做到只有管理员用户才能发布文章?
【发布时间】:2016-09-22 15:15:10
【问题描述】:

用户模型有一个属性 :admin 可以是真或假。我想进行验证,以便只有具有 admin = true 的用户才能发布文章或查看视图中的“新文章”按钮。

我正在使用设计 gem

控制器(articles_controller.rb):

class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /articles
  # GET /articles.json
  def index
    @articles = Article.paginate(page: params[:page], per_page: 4) 
  end

  # GET /articles/1
  # GET /articles/1.json
  def show
  end

  # GET /articles/new
  def new
    @article = current_user.articles.build
  end

  # GET /articles/1/edit
  def edit
  end

  # POST /articles
  # POST /articles.json
  def create
    @article = current_user.articles.build(article_params)

    respond_to do |format|
      if @article.save
        format.html { redirect_to @article, notice: 'Article was successfully created.' }
        format.json { render :show, status: :created, location: @article }
      else
        format.html { render :new }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /articles/1
  # PATCH/PUT /articles/1.json
  def update
    respond_to do |format|
      if @article.update(article_params)
        format.html { redirect_to @article, notice: 'Article was successfully updated.' }
        format.json { render :show, status: :ok, location: @article }
      else
        format.html { render :edit }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /articles/1
  # DELETE /articles/1.json
  def destroy
    @article.destroy
    respond_to do |format|
      format.html { redirect_to articles_url, notice: 'Article was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_article
      @article = Article.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

型号(article.rb):

class Article < ActiveRecord::Base

  belongs_to :user
  has_many :comments


  validates :title, length: { minimum: 5 }
  validates :title, uniqueness: true, uniqueness: { message: "This article title has already been posted."}
  validates :body, length: { minimum: 15 }
end

模型(user.rb):

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
    validates_uniqueness_of :username 
  has_many :articles
  has_many :comments 

end

架构:

ActiveRecord::Schema.define(version: 20160320222854) do

  create_table "articles", force: :cascade do |t|
    t.string   "title"
    t.text     "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "user_id"
  end

  create_table "comments", force: :cascade do |t|
    t.text     "body"
    t.integer  "user_id"
    t.integer  "article_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_index "comments", ["article_id"], name: "index_comments_on_article_id"
  add_index "comments", ["user_id"], name: "index_comments_on_user_id"

  create_table "contacts", force: :cascade do |t|
    t.string   "name"
    t.string   "email"
    t.text     "message"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "users", force: :cascade do |t|
    t.string   "username",               default: "",    null: false
    t.string   "email",                  default: "",    null: false
    t.string   "encrypted_password",     default: "",    null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,     null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.string   "confirmation_token"
    t.datetime "confirmed_at"
    t.datetime "confirmation_sent_at"
    t.string   "unconfirmed_email"
    t.datetime "created_at",                             null: false
    t.datetime "updated_at",                             null: false
    t.boolean  "admin",                  default: false
    t.string   "firstname"
    t.string   "lastname"
  end

  add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

end

查看/articles (index.html.erb):

 <div class="row">
    <!-- Blog article Content Column -->
    <div class="col-lg-8">
<% @articles.each do |article| %>
        <!-- Blog article -->

        <!-- Title -->
        <h4 style="font-size: 45.5px;"><%= link_to article.title, article %></h4>
                        <!-- Date/Time -->
        <p><span class="glyphicon glyphicon-time"></span> 
        <%= time_ago_in_words(article.created_at) %>
        </p>


        <!-- Author -->
        <p>
             Article By:<strong>  <%=  article.user.username %></strong>
        </p>

        <hr>

        <% end %>

<%= link_to "New article", new_article_path, class: "btn btn-default btn-xs" %>

    </div>



<!-- paginate -->

<%= will_paginate @articles %>

<br />

在此先感谢所有愿意提供帮助的优秀人士。

【问题讨论】:

  • 你能更新你的视图文件吗
  • 是的,我添加了视图文件。
  • 为了更好地支持用户角色,您可以使用 Pundit 或 CanCanCan gems。

标签: ruby-on-rails ruby devise


【解决方案1】:

您可以在应用程序控制器中添加过滤方法

def admin_access
  render(text: 'Unauthorised') and return unless current_user.admin
end

并在 Atricles 控制器或任何其他需要的地方使用它

before_filter :admin_access, only: [:new, :create, :edit, :update, :destroy]

在视图中,检查用户是否为管理员

<% if current_user.admin %>
  # new/edit/delete links
<% end %>

尽管不在视图中显示链接可以解决问题,但在服务器端有适当的授权逻辑总是更好。

【讨论】:

    【解决方案2】:

    在控制器中

    def new
      if current_user.admin
        @article = current_user.articles.build
      else
        redirect_to root_path and return #somewhere you want to redirect
      end
    end
    

    在视图中

    <% if current_user.admin %>
      <%= link_to "New article", new_article_path, class: "btn btn-default btn-xs" %>
    <% end %>
    

    【讨论】:

      【解决方案3】:

      New Article 链接显示给唯一的管理员。将条件添加到您的 link_to 标记。这只会隐藏链接。

      <%= link_to "New article", new_article_path, class: "btn btn-default btn-xs" if current_user.admin? %>
      

      假设您只希望管理员用户创建一篇新文章。然后你需要在你的应用程序中实现授权。试试cancancangem

      对于docsvideo

      【讨论】:

      • 隐藏链接并不能阻止用户在浏览器的地址栏中输入 URL users/newusers/123/edit
      • 我已经知道这就是我提到这两种情况的原因。 :)
      • “可以发布文章或在视图中看到“新文章”按钮”在问题中做出这样的回答。
      • 谢谢你们这就是我一直在寻找的答案,我会修复接下来的路线以防止这种情况发生。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 2016-08-07
      • 2022-11-09
      • 2023-03-19
      • 2019-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多