Skip to content

Instantly share code, notes, and snippets.

@harlow
Created August 30, 2016 18:59
Show Gist options
  • Save harlow/ccb529cab3b27534f5bc7e9e44d9746c to your computer and use it in GitHub Desktop.
Save harlow/ccb529cab3b27534f5bc7e9e44d9746c to your computer and use it in GitHub Desktop.
class Registration
# Make this model play nice with `form_for`. Gives us validations, initialize, etc
include ActiveModel::Model
# Accessors for the fields we are exposing in the form
attr_accessor :email, :password, :zip
# This is an implementation detail of our authentication (Clearance). It's ultimately going to
# sign this object in and that process expects a user object that has these fields available
delegate :remember_token, :id, to: user
# For this object to be valid, we want the child objects (user and profile) to be valid. This is
# the validation method that does this.
validate :validate_children
# We tell registration it's a user. This will keep it pointing to Users controller and allow it to use
# user translations
def self.model_name
User.model_name
end
# This is what our controller calls to save the user.
def save
if valid?
# Create a transaction. If any of the database stuff in here fails, they will raise an exception
# (because they are bang methods) and rollback the transaction.
ActiveRecord::Base.transaction do
user.save!
profile.save!
end
end
end
private
# Initialize the user object with the arguments that apply to user
def user
@user ||= User.new(email: email, password: password)
end
# initialize the profile object with the arguments that apply to profile
def profile
@profile ||= user.build_profile(zip: zip)
end
# the implementation of our validation method. We just delegate to our
# two child objects which define their validations (presence on all fields in this case)
def validate_children
if user.invalid?
promote_errors(user.errors)
end
if profile.invalid?
promote_errors(profile.errors)
end
end
# Errors on `user` or `profile` aren't helpful to us because `user.email` isn't on our form. `email` is however.
# Take all errors from our child objects and promote them to the same field on the base object. This will make
# them render properly on the form.
def promote_errors(child_errors)
child_errors.each do |attribute, message|
errors.add(attribute, message)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment