避免在Form类中重复代码

时间:2016-02-02 11:47:22

标签: ruby-on-rails

我创建了一个如下所示的表单类:

class UserForm
  include ActiveModel::Model

  attr_accessor :name, :phone_number,:address1, :address2

  validates :name, presence: true

  def create_user
    User.create! do |u|
      u.name = name
      u.phone_number = phone_number
      u.address1 = address1
      u.address2 = address2
    end
  end

  def update_user(user)
    user.name = name
    user.phone_number = phone_number
    user.address1 = address1
    user.address2 = address2

    user.save 
  end
end

当我使用类似UserForm.new({name: 'x', phone_number: 'z'})的哈希值初始化时,我创建了与实例变量一样多的attr_accessor。

如何避免重复创建和更新中的代码?我为用户提供了更多属性,并且我试图避免在创建和更新中重复所有这些属性。

2 个答案:

答案 0 :(得分:2)

改为使用Rails方式。

我会说你正在做的事情很可能是不必要的。在Rails中,控制器将输入传递给模型 - 模型处理验证该输入。 Form builders将绑定模型属性和错误处理为html。

所以"表格类"根本没有像Symfony 2这样的其他框架中的内容。实际上,您可能只是添加了另一级别的重复和间接,而不是干掉您的应用程序。

在rails中创建模型实例时,无需绑定属性1-1。 Rails模型初始化器和工厂方法采用属性哈希:

User.new(name: "Max", awesome: true) 
User.create(name: "Max", awesome: true) # this is just .new and .save

Rails的方法是设置表单输入,以便它们与模型属性对齐:

<%= form_for(@user) do |f| %>
  <div class="row">
   <%= f.label :name %>
   <%= f.text_input :name %>
  </div>
  <div class="row">
   <%= f.label :awesome %>
   <%= f.check_box :awesome %>
  </div>
<% end %>

然后在您的控制器中,您只需白名单并将参数传递给模型初始值设定项:

class UserController < ApplicationController

  before_action :set_user, only: [:show, :edit, :update, :destroy] 

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render :new
    end
  end

  def update
    if @user.update(user_params)
      redirect_to @user
    else
      render :edit
    end
  end

  private 

    def set_user
      @user = User.find(params[:id])
    end

    def user_params
      params.require(:user).permit(:name, :awesome)
    end
end

如果您想干掉控制器,可以使用responders和过滤器。如果您需要共享方法,您将使用关注点或经典继承。

def create
  @user = User.create(user_params)
  respond_with(@user)
end

要重复使用表单和表单组件,请使用partials

# app/views/users/new.html.erb
<h1>Create a new user</h1>
<% render partial: 'form' %>

# app/views/users/edit.html.erb
<h1>Editing <%= @user.name %></h1>
<% render partial: 'form' %>

答案 1 :(得分:0)

您可以创建一个方法,将实例变量公开为哈希...

class UserForm
  include ActiveModel::Model

  attr_accessor :name, :phone_number,:address1, :address2

  validates :name, presence: true

  def attrs
    (instance_variables.map{|i| [i.to_s[1..-1].to_sym, instance_variable_get(i)]}).to_h
  end

  def create_user
    User.create!(attrs) 
  end

  def update_user(user)
    user.update_attributes(attrs)
  end
end