0

ネストされた属性でエラーと闘っていますが、同時に警官エラーを修正しようとしています。というわけで、ここからがウォークスルーです。ジョブの価格に影響を与える可能性のあるネストされた属性を使用して、フォームでクーポン コードを送信できます。これは、クーポン コードが有効な場合にのみ発生します。このシナリオでは、クーポン コードは既に割り当てられているため、最初のコードif coupon_code && coupon.nil?がトリガーされます。フォームが戻ってくると、フラッシュ メッセージは正しく機能しますが、単純なフォームでは値が表示されません。インスタンス変数を使用して値を持つように単純なフォームを調整することはできますが、私のロジックでは、ここで何かが少しずれているように感じ始めています。また、のにおいがAssignment Branch Condition気になり始めています。私はこれを進めることができますが、ユーザーはコードを見たいと思っています。私もそうします。

コップ エラー:

app/controllers/payments_controller.rb:9:3: C: Assignment Branch Condition size for update is too high. [17.97/15]

コントローラー

class PaymentsController < ApplicationController
  rescue_from ActiveRecord::RecordNotFound, with: :route_not_found_error

  Numeric.include CoreExtensions::Numeric::Percentage

  def update
    @job = Job.find(params[:job_id])
    coupon_code = params[:job][:coupon_attributes][:code]
    coupon = validate_coupon(coupon_code)
    if coupon_code && coupon.nil?
      @coupon_code = coupon_code
      flash.now[:error] = t('flash_messages.coupons.id.not_found')
      render 'payments/new', layout: 'nested/job/payment'
    else
      update_job(@job, coupon)
      update_coupon(coupon, @job) if coupon
      redirect_to @job.vanity_url
    end
  end

  def new
    @job = Job.find(params[:job_id])
    return if reroute?(@job)
    render 'payments/new', layout: 'nested/job/payment'
  end

  private

  def update_job(job, coupon)
    job.start_at = DateTime.now
    job.end_at = AppConfig.product['settings']['job_active_for_day_num'].days.from_now
    job.paid_at = DateTime.now
    job.price = price_job(coupon)
    # job.save
  end

  def validate_coupon(coupon_code)
    return nil unless coupon_code.present?
    coupon = Coupon.active.find_by_code(coupon_code)
    return nil unless coupon.present?
    coupon
  end

  def price_job(coupon)
    price = AppConfig.product['settings']['job_base_price']
    return price unless coupon
    price = coupon.percent_discount.percent_of(price)
    price
  end

  def update_coupon(coupon, job)
    coupon.job_id = job.id
    coupon.executed_at = DateTime.now
    coupon.save
  end
end

ビュー:

ruby:
  content_for :body_id_class, 'PaymentNew'
  content_for :js_instance, 'viewPaymentNew'
  content_for :browser_title, 'Payment'
  job_base_price = AppConfig.product['settings']['job_base_price']
  coupon_code = @coupon_code ||= ''

= simple_form_for(@job, url: job_payment_path, html: { id: 'payment-processor-form' }) do |j|
  div[class='row']
    div[class='col-md-12']
      div[class='panel panel-default']
        div[class='panel-heading']
          h3[class='panel-title']
            |Total Cost
        div[class='panel-body']
          h2[class='job-cost' data-initial = "#{job_base_price}"]
            = number_to_currency(job_base_price)
        div[class='panel-heading']
          h3[class='panel-title']
            |Have a coupon?
        div[class='panel-body']
          div[class='row-inline']
            div[class='row-block row-block-one']
              = j.simple_fields_for :coupon_attributes, @job.coupon do |c|
                = c.input_field :code, maxlength: 50, id: 'coupon-code', class: 'form-control', data: { 'initial' => 0 }, value: coupon_code
            div[class='row-block']
              button[type='button' class='btn btn-primary' id='coupon-verify' ]
                |Verify
            p[class='help-hint']
              = t('simple_form.hints.coupon.code')

  div[class='row']
    div[class='col-md-12']
      = j.button :button, type: 'button', class: 'btn-primary text-uppercase', id: 'purchase-job' do
        = job_posting_button_step_label

アップデート

  1. このコードをリファクタリングして、以下の投稿で動作するようにします。factorygirl がモデルの関連付けを作成するのを修正NoMethodError: 未定義のメソッド
4

1 に答える 1

1

その太った古いコントローラーで、かなりの数のコードの臭いが発生しています。それらのほとんどは、モデル層ですべてがうまく機能しておらず、ドメインをうまくモデリングしていないという症状のようです。

次のようなことを検討してください。

class Job < ActiveRecord::Base
  has_many :payments
end

class Payment < ActiveRecord::Base
  belongs_to :job
  belongs_to :coupon
end

class Coupon < ActiveRecord::Base
  validates_uniqueness_of :code
end

これにより、カウンターローラーは、たくさんの猫を集めようとするのではなく、単一のリソースを CRUD することに集中できます。

それでは、クーポンのビジネス ロジックを適用する方法を見てみましょう。

class Payment < ActiveRecord::Base
  belongs_to :job
  belongs_to :coupon

  validate :coupon_must_be_active

  attr_writer :coupon_code

  def coupon_code=(code)
    coupon = Coupon.find_by(code: code)
    @coupon_code = code
  end

  private 
  def coupon_must_be_active
    if coupon
      errors[:coupon] << "must be active." unless coupon.active?
    elsif @coupon_code.present? 
      errors[:coupon_code] << "is not valid."
    end
  end
end

カスタム属性ライターは、コードからクーポンを読み込みます。検証により、ビジネス ロジック ルールが設定されます。

ジョブの価格設定に関しては、実際に同じことを行う必要があります。

class Job < ActiveRecord::Base
  after_initialize :set_price

  def set_price
    self.price ||= AppConfig.product['settings']['job_base_price']
  end
end

class Payment < ActiveRecord::Base
  after_initialize :set_price
  validates_presence_of :job

  def net_price
     return job.price unless coupon
     job.price * (coupon.percent_discount * 00.1)
  end

  # ...
end

次に、コントローラーを次のように記述します。

class PaymentsController

  before_action :set_job

  # GET /jobs/:job_id/payments/new
  def new
    @payment = @job.payments.new
  end

  # POST /jobs/:job_id/payments
  def create
    @payment = @job.payments.create(payment_params)
  end

  # PATCH /jobs/:job_id/payments/:id
  def update
    @payment = @job.payments.find(params[:id])
  end

  private

    def set_job
      @job = Job.find(params[:job_id])
    end

    def payment_params
      params.require(:payment)
            .permit(:coupon_code)
    end
end

次に、フォームを次のように簡単に設定できます。

= simple_form_for([@job, @payment]) do |f|
  = f.input :coupon_code
  = f.submit

名誉システムを実装するつもりでない限り、ユーザーから価格を受け取りたくないことに注意してください。関連付けコールバックを設定して、モデルから価格を取得する必要があります。

于 2016-03-18T20:45:33.027 に答える