通过rails中的服务创建记录时引发的ActiveModel :: ForbiddenAttributesError

时间:2016-05-25 16:12:27

标签: ruby-on-rails

当我尝试使用Form ObjectService创建宣传活动时,我遇到了一些麻烦。在我的应用程序中,我有各种类型的Promotion,我在:type列中使用单表继承存储它们。我有促销类型的子类,例如Promotion::CompensationSchemePromotion::CouponCampaignPromotion::RulesMatch ..等。

promotions / new.html.slim

= form_for(@promotion_new_form), url: admin_promotions_path do |f|
  = f.text_field :name
  = f.select :type

:type select的选项哈希是

{'Coupon Campaign' => 'Promotion::CouponCampaign', 'Rules Match' => 'Promotion::RulesMatch'}

PromotionNewForm 类(表单对象)中,我检查表单字段的有效性,并将创建过程传递给名为Promotion::CreateCampaign的服务。

Promotion :: CreateCampaign (服务对象)中:

class Promotion::CreateCampaign < AppService

    def initialize params
        @promotion_class = params[:type].constantize
        @params = params.except!(:type)
    end

    def call
        promotion = @promotion_class.new(@params)
        puts promotion.inspect
        SuccessStatus.new(promotion)
    end
end

promotions_controller

   def create
        results = @promotion_new_form.submit(params[:promotion_new_form])
        if results.success?
            puts results.data.inspect
            # redirect_to edit_admin_promotion_path(results.data)
        else
            render 'new'
        end
    end

我现在有这个错误:

  

Admin :: PromotionsController #create

中的ActiveModel :: ForbiddenAttributesError

基本上说明我的服务对象中的行promotion = @promotion_class.new(@params)具有禁止的属性。我知道通常如果您在控制器中处理表单,则需要strong_parameters并使用params.permit()让params通过..但现在我在服务对象中处理它。我不知道为什么我仍然要这样做,如果是这样我怎么能这样做..

1 个答案:

答案 0 :(得分:1)

您正在将params[:promotion_new_form]传递给您的服务类。 paramsActionController::Parameters类的实例。当活动模型接收到此类的一个实例时,它将应用strong_parameters检查。

所以,你有几个选择。

选项1(推荐)

将已清理的params传递给您的服务。

results = @promotion_new_form.submit(params.require(:promotion_new_form).permit(:your, :promotion, :fields))

选项2(不推荐)

将params的原始Hash传递给您的服务,并在那里过滤/验证模型属性。

results = @promotion_new_form.submit(params[:promotion_new_form].to_unsafe_hash)

选项3(最后手段)

不要使用质量分配方法(createnewupdate_attributes等),而是逐个初始化每个属性。

# Controller
results = @promotion_new_form.submit(params[:promotion_new_form])

# Service
promotion = @promotion_class.new
promotion.field1 = @params.field1
promotion.field2 = @params.field2
SuccessStatus.new(promotion)