【问题标题】:Trying to have 2 forms pass to 2 different controllers from one view试图从一个视图将 2 个表单传递给 2 个不同的控制器
【发布时间】:2016-04-14 01:26:08
【问题描述】:

我在一个视图中有 2 个表单,如果用户是版主,则显示一个,如果是普通用户,则显示另一个,并且它们都将信息发送到 2 个不同的控制器。我的问题是,如果它是普通用户,为他们显示的表单使用了错误的控制器。

这里是编码

类别/new.html.erb

<% if current_user.mod_of_game? @guide %>

 <%= form_for([@guide, @category], url: guide_categories_path) do |f| %>
   <%= render 'shared/error_messages', object: f.object %>

  <%= f.label :name, "Category name" %>
  <%= f.text_field :name %>

  <%= f.submit "Next"  %>
<% end %>

<% else %>


<%= form_for([@guide, @check_category], url: check_category_post_path) do |f| %>
 <%= render 'shared/error_messages', object: f.object %>

 <%= f.label :name, "Category name" %>
 <%= f.text_field :name %>

 <%= f.submit "Next"  %>
<% end %>


<% end %>

类别控制器

before_action :mod_checker, only: [:create]

 def new
    @guide = Guide.friendly.find(params[:guide_id])
    @category = Guide.friendly.find(@guide.id).categories.new
    @check_category = CheckCategory.new
end


 def create
 @guide = Guide.friendly.find(params[:guide_id])
   @category = Guide.friendly.find(@guide.id).categories.new(category_params)

 if ((@category.save) && (current_user.mod_of_game? @guide))

  flash[:info] = "guide category added succesfully!"
  redirect_to @guide
  else

   render 'new'

   end
    end

private

def category_params
    params.require(:category).permit(:name)
end

 def mod_checker
 @guide = Guide.friendly.find(params[:guide_id])
 unless current_user.mod_of_game? @guide
  flash[:danger] = "Sorry something went wrong!"
  redirect_to root_path
 end
end

check_categories 控制器

def new
    end

def create
if @check_category.save

            flash[:info] = "Game category added successfully. A mod will apporve it shortly."
          redirect_to @guide

   else
   render 'new'
   end

    end

private


def check_category_params
    params.require(:check_category).permit(:name)
end

路线

resources :guides do
   resources :categories,     only: [:new, :create, :edit, :update]
end

  resources :check_categories,     only: [:new, :edit, :update]

  match 'guides/:guide_id/categories/' => 'check_categories#create', :via => :post, as: :check_category_post

抱歉编码有点乱,将它放在代码块中的 4 个空格让我的编码间隔很奇怪。

当我有一个非版主用户提交表单时,类别控制器中的 before 操作将运行并且我被重定向到主页。我不知道为什么会这样,因为提交路径应该转到非版主用户的 check_categories 控制器,而 check_categories 控制器没有 before 过滤器。

为什么它在我没有用于该表单的控制器中使用 before 过滤器?我该如何解决?

构建此应用以更好地学习 Rails。所以我只能假设缺乏 Rails 知识导致我做错了。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 model-view-controller controller


    【解决方案1】:

    拥有两个具有相同代码的表单(path 除外)的不良做法 - 与 DRY Don't Repeat Yourself 相违背。

    正如@Akash 所说,这听起来像是authorization 的工作。

    此外,它还表示您的代码的底层结构存在问题。具体来说,你有一个antipatternCheckCategory(你可以把它全部放到Category 模型中):

    #config/routes.rb
    resources :guides do
       resources :categories, only: [:new, :create, :edit, :update] do
          patch :approve, on: :member
       end
    end
    
    #app/models/category.rb
    class Category < ActiveRecord::Base
        before_action :set_guide
    
        def new
            @category = current_user.categories.new
            flash[:notice] = "Since you are not a moderator, this will have to be approved." unless current_user.mod_of_game? @guide
        end
    
        def create
            @category = current_user.categories.new category_params
            @category.guide = @guide
            @category.save
        end
    
        def approve
            @category = @guide.categories.find params[:id]
            @category.approve
        end
    
        private
    
        def set_guide
            @guide = Guide.find params[:guide_id]
        end
    end
    
    #app/views/categories/new.html.erb
    <%= form_for [@guide, @category] do |f| %>
       <%= render 'shared/error_messages', object: f.object %>
    
       <%= f.label :name, "Category name" %>
       <%= f.text_field :name %>
    
       <%= f.submit "Next"  %>
    <% end %>
    

    以上将解决您的大部分结构问题。

    --

    要解决授权问题,您最好在模型中指明该类别是否“已批准”:

    #app/models/category.rb
    class Category < ActiveRecord::Base
       enum status: [:pending, :approved]
    
       belongs_to :user
       belongs_to :guide
       validates  :user, :guide presence: true
       before_create :set_status
    
       def approve
          self.update status: "approved"
       end
    
       private
    
       def set_status
          self[:status] = "approved" if self.user.mod_of_game? self.guide
       end
    end
    

    --

    如果我理解正确,您希望允许任何人创建一个类别,但非模组必须由版主“检查”他们的类别。

    上面的代码应该会为你实现这个。

    您需要添加一个 gem,例如 CanCan CanCanCan 来实现一些授权:

    #app/views/categories/index.html.erb
    <% @categories.each do |category| %>
       <%= link_to "Approve", guide_category_approve_path(@guide, category) if category.waiting? && can? :update, Category %>
    <% end %>
    

    【讨论】:

    • 感谢您的详细解答。我过去看过 CanCanCan 和权威人士,但他们看起来更像是一个可以主持所有事情的主持人,例如。所有帖子。我需要它,因此只有类别的版主才能审核该类别中的内容。我有这个设置,所以信息会转到一个单独的数据库以由 mod 批准,如果获得批准,它将被移动到要显示的主数据库。加上这种方式,db 显示信息的速度更快,因为不必检查是否每个信息都被批准。
    • 而且我也会有版本控制。如果一个普通用户编辑它需要首先由一个mod批准的信息,CanCanCan没有那种灵活性,它需要在数据库中创建2个相同的记录,一个批准一个不批准,未批准的需要一旦批准拥有 2 分贝就替换另一个,这会变得更容易和更可控。
    【解决方案2】:

    使用“Cancan”宝石并给予授权

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多