Last active
June 26, 2021 12:14
-
-
Save kizzx2/4722784 to your computer and use it in GitHub Desktop.
A clean and elegant approach to partial object validation with Rails + Wicked wizards (using session to store the partial object)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Post < ActiveRecord::Base | |
attr_accessible :body, :price, :title | |
validates_presence_of :title | |
validates_length_of :title, minimum: 10 | |
validates_presence_of :body | |
validates_numericality_of :price, greater_than: 0 | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PostWizardController < ApplicationController | |
include Wicked::Wizard | |
steps '1_title', '2_body', '3_price' | |
# Define partial validation in a clear tabular format | |
VALIDATIONS = { | |
'1_title' => [:title], | |
'2_body' => [:title, :body], | |
'3_price' => [:title, :body, :price], | |
}.freeze | |
# Here PartialPost is a private property of this controller not shared in any | |
# other part of the code so we make it a nested class. | |
class PartialPost < Post | |
attr_accessor :step | |
# For message passing only | |
attr_accessor :session | |
def self.model_name | |
Post.model_name | |
end | |
def save | |
# In the last step, actually persist to database | |
if self.step == VALIDATIONS.keys.last | |
rv = super | |
session.delete(:post_wizard) if rv | |
self.session = nil | |
return rv | |
end | |
# Clear out the session because we can't save session within session | |
self.session = nil | |
# Trigger ActiveRecord's validation | |
self.valid? | |
(self.errors.messages.keys - VALIDATIONS[self.step]).each do |k| | |
self.errors.messages.delete(k) | |
end | |
# Insert complicated custom validation manipulation here | |
self.errors.empty? | |
end | |
end | |
def index | |
session[:post_wizard] ||= {} | |
session[:post_wizard][:post] = PartialPost.new | |
redirect_to wizard_path(steps.first) | |
end | |
def show | |
if session[:post_wizard].try(:[], :post).present? | |
@post = session[:post_wizard][:post] | |
end | |
render_wizard | |
end | |
def update | |
@post = session[:post_wizard][:post] | |
@post.attributes = params[:post] | |
@post.step = step | |
@post.session = session | |
render_wizard(@post) | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment