Instantly share code, notes, and snippets.

@kizzx2 /post.rb
Last active Mar 8, 2018

Embed
What would you like to do?
A clean and elegant approach to partial object validation with Rails + Wicked wizards (using session to store the partial object)
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
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