Standard rails create action

Rails has taught me some really good best practices. Let’s look at a default rails create action

def create
  @post =
  respond_to do |format|
      format.html { redirect_to @post, notice: 'Post was successfully created.' }
      format.html { render :new }

I try not to deviate too much from this and nor should you. If returns true. return a 201 status code. If returns false re-render the :new action. So you can let the user fix the form.

Often I will see things like this.

def create
  if params[:something]
    @post = Post.create(post_params)
    @post = Post.create(other_params)
  redirect_to posts_path

At first glance this looks clean. But if you look closer. There is a subtle problem here. If the post object fails validation and fails to create, The action redirects to the index action where all new instaces are creating. The @post object has lost any knowlege of the params and it will not get to oportunity to display the errors from the object. You’ll have to resort to things like flash[:notice] = "@post.errors.full_messages.join()"… ugh.

Active record gives us a nice interface for displaying errors on an object.

class Post < ActiveRecord::Base
  validates :title, presence: true
irb(main):001:0> p =
=> #<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>
irb(main):002:0> p.valid?
=> false
irb(main):003:0> p.errors
=> #<ActiveModel::Errors:0x007fe0ca9e4b68 @base=#<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>,
@messages={:title=>["can't be blank"]}>

When you call OR @post.valid? errors are added to the @post object so they can be displayed within the form.

Digging even deeper… Check out ActiveModel::Model. It will give you this same object interface without needing database backed model. Powerful stuff.