我认为这是 Active Model 大放异彩的一个案例。我喜欢用它来实现没有额外依赖的表单对象。我不知道您的具体情况,但我在下面粘贴了一个小演示,您应该能够适应您的情况。
最大的好处是您不会使用支持配置文件更新的方法污染您的控制器或模型。它们可以被提取到一个单独的模型中,从而简化事情。
第 1 步:将 dob 存储在 users 中
您的users 表应该有一个dob 类型为date 的列。例如:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name, null: false
t.date :dob, null: false
end
end
end
不要在模型中添加任何花哨的东西:
class User < ActiveRecord::Base
end
第二步:添加Profile
将以下内容放入app/models/profile.rb。解释见 cmets。:
class Profile
# This is an ActiveModel model.
include ActiveModel::Model
# Define accessors for fields you want to use in your HTML form.
attr_accessor :dob_string
# Use the validatiors API to define the validators you want.
validates :dob_string, presence: true
validate :dob_format
# We store the format in a constant to keep the code DRY.
DOB_FORMAT = '%m/%d/%Y'
# We store the user this form pertains to and initialize the DOB string
# to the one based on the DOB of the user.
def initialize(user)
# We *require* the user to be persisted to the database.
fail unless user.persisted?
@user = user
@dob_string = user.dob.strftime(DOB_FORMAT)
end
# This method triggers validations and updates the user if validations are
# good.
def update(params)
# First, update the model fields based on the params.
@dob_string = params[:dob_string]
# Second, trigger validations and quit if they fail.
return nil if invalid?
# Third, update the model if validations are good.
@user.update!(dob: dob)
end
# #id and #persisted? are required to make form_for submit the form to
# #update instead of #create.
def id
@user.id
end
def persisted?
true
end
private
# Parse dob_string and store the result in @dob.
def dob
@dob ||= Date.strptime(dob_string, DOB_FORMAT)
end
# This is our custom validator that calls the method above to parse dob_string
# provided via the params to #update.
def dob_format
dob
rescue ArgumentError
errors[:dob] << "is not a valid date of the form mm/dd/yyyy"
end
end
第 3 步:使用控制器中的表单
在ProfilesController 中使用Profile:
class ProfilesController < ApplicationController
def edit
# Ensure @profile is set.
profile
end
def update
# Update the profile with data sent via params[:profile].
unless profile.update(params[:profile])
# If the update isn't successful display the edit form again.
render 'edit'
return
end
# If the update is successful redirect anywhere you want (I chose the
# profile form for demonstration purposes).
redirect_to edit_profile_path(profile)
end
private
def profile
@profile ||= Profile.new(user)
end
def user
@user ||= User.find(params[:id])
end
end
第 4 步:使用form_for 呈现表单
在app/views/profiles/edit.html.erb 中使用form_for 显示表单:
<%= form_for(@form) do |f| %>
<%= f.label :dob_string, 'Date of birth:' %>
<%= f.text_field :dob_string %>
<%= f.submit 'Update' %>
<% end %>
第 5 步:添加路由
记得添加路由到config/routes.rb:
Rails.application.routes.draw do
resources :profiles
end
就是这样!