如何避免控制器和模型中的重复卫生?

时间:2016-06-11 11:31:56

标签: ruby-on-rails ruby

我在Rails中有这个方法返回params:

def customer_params
  params.require(:treatment_booking).require(:customer)
end

我想从:phone中删除空格并返回整个哈希值。我可以这样做:

params.require(:treatment_booking).require(:customer).merge(:phone => params[:treatment_booking][:customer][:phone].gsub(/\s+/, ""))

..但我认为它有点不优雅,因为我必须引用我已经调用方法的哈希的整个路径。还有更好的方法吗?

答案可以是Ruby和Rails。

一般来说,我所做的是在预订控制器中更新客户。客户可以保留,但没有密码,所以我不能让它改变它的数据 - 只添加。

这是控制器中的内容:

  def create
    customer = Customer.find_or_create_by(email: customer_params[:email])
    if not customer.persisted?
      customer.phone = customer_params[:phone] if not customer_params[:phone].empty?
      customer.name = customer_params[:name] if not customer_params[:name].empty?
      save_customer(customer)
    elsif (customer.phone != customer_params[:phone] || customer.name.downcase != customer_params[:name].downcase)
      customer.phone = customer_params[:phone] if customer.phone.empty?
      customer.name = customer_params[:name] if customer.name.empty?
      save_customer(customer)
      redirect_to :back, notice: "This email address has been used before, you can register it or use the same Name and Phone"
      return
    else
      set_session_customer(customer.id)
    end

  < .. .. >
  end

2 个答案:

答案 0 :(得分:2)

我认为控制器无需清理参数。但是模型的责任是确保其属性有效。

要清理模型属性,我会将自定义setter添加到Customer模型中,如下所示:

# in app/models/customer.rb
def phone=(phone)
  write_attribute(:phone, phone.gsub(/\s+/, ''))
end

并保持控制器中的customer_params不变。

解决您的评论:您的控制器中有很多事情发生。而IMO控制器很难理解和重构。特别是因为我不知道方法save_customerset_session_customer做了什么以及你需要对变更属性有多严格。

我认为将更新代码移到Customer模型中是有意义的。这使得测试更容易。我使用了Rails' Dirty Attributes

# in the controller
def create
  existing_customer = Customer.find_by(present_customer_params.fetch(:email))

  if existing_customer
    if existing_customer.contact_detail_update(present_customer_params)
      save_customer(existing_customer)
      redirect_to(
        :back,  notice: 'This email address has been used before, you can register it or use the same Name and Phone'
      ) and return
    else
      set_session_customer(existing_customer.id)
    end
  else
    new_customer = Customer.create(present_customer_params)
    save_customer(new_customer)
  end

  # ...
end

private
  def present_customer_params
    # excludes blank values from the customer_params
    customer_params.select { |_, v| v.present? }
  end

# in the `Contact` model
def contact_detail_update(attrs = {})
  contact_attributes = [:phone, :name]

  # update the customers attributes and let existing customer setters to their job
  attributes = attrs.slice(*contact_attributes) 

  # check case-insensitively if there were any non-trivial changes 
  changes.slice(*contact_attributes).values.any? do |change| 
    change.first.casecmp(change.last) != 0
  end
end

我不确定这是否能回答您的评论,但也许这个想法对您未来的重构很有帮助......

答案 1 :(得分:0)

回调是这类任务的有用工具:

class Customer < ActiveRecord::Base
  before_save :sanitize_phone

  def sanitize_phone
    self.phone = phone.gsub(/\s+/, '')
  end
end

您还可以使用ActiveModel::Dirty提供的方法,使用回调来拒绝对现有属性的更改。 http://api.rubyonrails.org/classes/ActiveModel/Dirty.html

before_save :reset_changed_attributes

def reset_changed_attributes
  phone = phone_was if phone_changed? 
  name = name_was if name_changed? 
end