home icon contact icon rss icon

By: Matt Lins

Factory_Girl Sequences as Lazy Attributes

I just ran into a problem with factory_girl sequences. The problem was I defined my Factories like this:

1
2
3
4
5
6
7
8
9
10
11
12
# Sequences

Factory.sequence :name do |n|
  'name' + n.to_s
end

# Manufacturers

Factory.define :manufacturer do |m|
  m.name Factory.next(:name)
  m.active true
end

Assume I have a validates_uniqueness_of validation on name in Manufacturer:

1
2
3
4
5
class Manufacturer < ActiveRecord::Base

  validates_uniqueness_of :name

end

Now, lets say I created a couple of manufacturers in my test setup:

1
2
3
4
5
6
7
8
9
require File.dirname(__FILE__) + '/../test_helper'

class ProductTest < ActiveSupport::TestCase

  setup do
    2.times { Factory(:manufactuer) }
  end

end

Ok, this setup block will fail because it's creating 2 manufacturers with the same name. But, I thought I was using a sequence? Well, the sequence is only sequenced during the definition of the factories. Meaning, in the above example Factory#next was only called once.

Luckily, factory_girl allows us to use something called lazy attributes. We can just wrap our sequence with some curly brackets, like so:


m.name { Factory.next(:name) }

Now everytime I create a new Manufacturer the sequence will generate a unique name. Nice! Maybe if I'd taken some more time to RTFM, I wouldn't have wasted time on this problem. Regardless, I thought maybe I'd be able to help someone else out that runs into this.

More about factory_girl

By: Matt Lins

Dissecting Rails Validations - Part II

The loading of the built-in validators

Well, it looks as if my posts will be irrespective of the actual chronology of events involved in validation. At least from a Rails start-to-finish call stack perspective. This post will venture back before those events discussed in Part I. The reason being, I forgot to mention how the Rails built-in validators are loaded and executed.

When your model's class definition is encountered(during initialization), all of the method calls to the built-in validators are ran. Let's say we have a model that looks like this:

1
2
3
class Supplier < ActiveRecord::Base
  validates_uniqueness_of :name   
end

When #validates_uniqueness_of is called, it jumps to ActiveRecord::Validations::ClassMethods, which was mixed in with ActiveRecord::Base during initilization earlier. We're not going to look at this method in whole because it's too long. The important part is that it makes use of #validates_each. I'd like to talk about #validates_each because it is the heart of almost all the built-in validators(some can't use it). Here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def validates_each(*attrs)
  options = attrs.last.is_a?(Hash) ? attrs.pop.symbolize_keys : {}
  attrs   = attrs.flatten

  # Declare the validation.
  send(validation_method(options[:on] || :save)) do |record|
    # Don't validate when there is an :if condition and that condition is false
    unless options[:if] && !evaluate_condition(options[:if], record)
      attrs.each do |attr|
        value = record.send(attr)
        next if value.nil? && options[:allow_nil]
        yield record, attr, value
      end
    end
  end
end

After the first couple of lines you see this:


send(validation_method(options[:on] || :save)) do |record|

This line of code is using the Ruby #send method to make a dynamic call to whatever #validation_method returns. Let's look at it:

1
2
3
4
5
6
7
def validation_method(on)
  case on
    when :save   then :validate
    when :create then :validate_on_create
    when :update then :validate_on_update
  end
end

When you declare your validation in your model, :on is an optional parameter. So, if we only wanted to run our validation on only the creation of records, we could do this:

1
2
3
class Supplier &gt; ActiveRecord::Base
  validates_uniqueness_of :name, :on => :create   
end

The #validation_method method will tell the #send method back in #validates_each where to declare the validator. Assuming we pass don't pass anything for the :on parameter it'll be declared by #validate(both create and update). Don't get these methods confused with low-level #validate, #validate_on_create and #validate_on_update of which you can override in your models. These are defined outside of Validations::ClassMethods and they have a different amount of parameters. Lets look at Validations::ClassMethods#validate:

1
2
3
4
def validate(*methods, &block)
  methods << block if block_given?
  write_inheritable_set(:validate, methods)
end

Validators can be methods, classes or blocks. This method will handle whatever you throw at it and toss it onto the array of validations to be ran whenever #valid? is called. It's using a method called #write_inheritable_set to store the array (read more about it in the inheritable_attributes.rb file).

Now, if you remember correctly from Part I the ActiveRecord::Base#save call is actually aliased to ActiveRecord::Validations#save_with_validation. This method makes a call to ActiveRecord::Validations#valid?. Let's dig into it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def valid?
  errors.clear

  run_validations(:validate)
  validate

  if new_record?
    run_validations(:validate_on_create)
    validate_on_create
  else
    run_validations(:validate_on_update)
    validate_on_update
  end

  errors.empty?
end

First, it clears the errors object. The errors object is defined by the ActiveRecord::Errors class, which mixes in Enumerable. You can add errors with #add and clear them with #clear etc. Anytime a validator encounters a problem with your model it adds an error. Next, #valid? calls #run_validations with :validate as a parameter(validation_method). Remember, these are validations that are called on both create and update. Continuing, it determines whether the record is new, it calls #run_validations again with the appropriate parameter(validation_method). Lastly, it returns the result of the expression errors.empty?. So, if any problems occurred during #run_validations, then the validator would have added an error to the enumerable causing #valid? to return false. Let's look at #run_validations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def run_validations(validation_method)
  validations = self.class.read_inheritable_attribute(validation_method.to_sym)
  if validations.nil? then return end
  validations.each do |validation|
    if validation.is_a?(Symbol)
      self.send(validation)
    elsif validation.is_a?(String)
      eval(validation, binding)
    elsif validation_block?(validation)
      validation.call(self)
    elsif validation_class?(validation, validation_method)
      validation.send(validation_method, self)
    else
      raise(
        ActiveRecordError,
        "Validations need to be either a symbol, string (to be eval'ed), proc/method, or " +
         "class implementing a static validation method"
      )
    end
  end
end

It grabs all the validations based on the validation_method passed using the #read_inheritable_attribute (look in the inheritable_attributes.rb file to find out why this is used). Next, it iterates through each of the validations. It does a check to see if the validation is a method, class or a block and executes it appropriately. Remember, if these validations encounter problems with the model data, they'll add an error onto the @errors enumerable causing #valid? to return false. Let's tie it all together with a review of the #save_with_validation method:

1
2
3
4
5
6
7
def save_with_validation(perform_validation = true)
  if perform_validation && valid? || !perform_validation
    save_without_validation
  else
    false
  end
end

If #valid? returns true(and you didn't pass false to #save), then #save_with_validation makes a call to #save_without_validation, which is actually aliased back to ActiveRecord::Base#save thus completing our save. Remember, ActiveRecord::Base#save is actually aliased to #save_with_validation so that validations can happen. Confused? Well, this is done with #alias_method_chain. Also, you may need to review Part I.

That should do it for another part to this series. If I feel the need to write Part III, we'll probably dive into what each of the built-in validators is actually doing.

By: Matt Lins

Can't find that Rails Method? (alias_method_chain)

I've been digging through the core more and more. One thing that still throws me off once in a while are method declarations that I can't seem to find. Naturally, I first do a search for the method name in a bunch of files. When it doesn't show up, I become frustrated because even if it was aliased, it should still come up in search. Well, if that's the case, look no further than a call to #alias_method_chain(usually). Even though I was aware of this method(it's nothing new), it still throws me off. I just need to remember anytime I see "with" or "without" in the method name, I should probably search for a call to #alias_method_chain.

For those of you not aware of what it is, here is the code(aliasing.rb):

1
2
3
4
5
6
7
8
def alias_method_chain(target, feature)
  # Strip out punctuation on predicates or bang methods since
  # e.g. target?_without_feature is not a valid method name.
  aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
  yield(aliased_target, punctuation) if block_given?
  alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target
  alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
end

It is used to DRY up the common aliasing pattern of:

1
2
alias_method :foo_without_feature, :foo
alias_method :foo, :foo_with_feature

This is used a lot in the Rails core. It is nice, but when you're not aware of it, it can certainly wear on you when trying to understand some code. I know it's a method that has been talked about plenty, but it's one of those things that is hard to search for when you're actually trying to solve the mystery it created.

By: Matt Lins

Dissecting Rails Validations - Part I

The road from save to validation.

Rails validations seem simple on the outside, but have you ever taken the time to understand what's really going on? What actually happens when you do model.save? I ran into a problem one day and I decided to take a gander and figure out how it all works. It was a little difficult. The Rails core can be very daunting. With the mix-ins, aliases and the enormity of the ActiveRecord code base, one could spend hours trying to figure it out. Well, I did and I'm going to try to explain it.

To start, I have my Rails application froze to 1.2.3 and I can easily browse the code by looking in my vendors/rails/ directory(you could check it out of SVN if you desire, to follow along). All the files I mention will be relative to that path. I began my journey in the activerecord/validations.rb file. It contains a contains two ActiveRecord classes: ActiveRecord::Errors and ActiveRecord:RecordInvalid and a module: Validations, which contains another module: Validations::ClassMethods. Well, this file gave me a nice idea of how things like validates_presence_of works(which I'll explain later), but I wanted to know more. Specifically, during the save process, when do validations get called and from where?

Well, I scanned right over some clues in activerecord/validations.rb and hastily decided to go right into the heart of ActiveRecord: ActiveRecord::Base in activerecord/base.rb. I was puzzled when I found the #save and #save! methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
# * No record exists: Creates a new record with values 
#   matching those of the object attributes.
# * A record does exist: Updates the record with 
#   values matching those of the object attributes.
def save
  create_or_update
end
      
# Attempts to save the record, but instead of just returning false if it couldn't happen, 
# it raises a RecordNotSaved exception
def save!
  create_or_update || raise(RecordNotSaved)
end

Naturally, I moved on to #create_or_update, to find:

1
2
3
4
5
def create_or_update
  raise ReadOnlyRecord if readonly?
  result = new_record? ? create : update
  result != false
end

Getting closer, but not quite what I'm looking for. This method checks and raises an exception if the record is read-only. Then it determines if the record is new and calls the appropriate method for a create or update.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Updates the associated record with values matching those of the instance attributes.
# Returns the number of affected rows.
def update
  connection.update(
    "UPDATE #{self.class.table_name} " +
    "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
    "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}",
    "#{self.class.name} Update"
  )
end

# Creates a record with values matching those of the instance attributes
# and returns its id.
def create
  if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name)
    self.id = connection.next_sequence_value(self.class.sequence_name)
  end

  self.id = connection.insert(
    "INSERT INTO #{self.class.table_name} " +
    "(#{quoted_column_names.join(', ')}) " +
    "VALUES(#{attributes_with_quotes.values.join(', ')})",
    "#{self.class.name} Create",
    self.class.primary_key, self.id, self.class.sequence_name
  )

  @new_record = false
  id
end

Where does validation come into play? We're already building SQL? Well this stumped me for about 10 seconds. Then I realized somewhere they must be mixing in the validation functionality. Logically, I headed back to activerecord/validations.rb to find what I overlooked:

1
2
3
4
5
6
7
8
def self.included(base) # :nodoc:
  base.extend ClassMethods
  base.class_eval do
    alias_method_chain :save, :validation
    alias_method_chain :save!, :validation
    alias_method_chain :update_attribute, :validation_skipping
  end
end

This code is aliasing the Base#save method to Validations#save_with_validation, which is mixed in just prior. To do so, it uses a built-in rails convenience method: #alias_method_chain. This happens when the module is loaded by using self.included.

I really enjoy the design of ActiveRecord. It is totally usable outside of Rails. Not only that, if you don't need validation then you simply don't load activerecord/validation.rb(Rails does this by default during initialization). But, just because you load the Validations module, doesn't mean you actually need to validate on save. As seen in the overridden methods below, you can simply pass false as a parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# The validation process on save can be skipped by passing false. The regular Base#save method
# is replaced with this when the validations module is mixed in, which it is by default.
def save_with_validation(perform_validation = true)
  if perform_validation && valid? || !perform_validation
    save_without_validation
  else
    false
  end
end

# Attempts to save the record just like Base#save but will raise a RecordInvalid exception 
# instead of returning false if the record is not valid.
def save_with_validation!
  if valid?
    save_without_validation!
  else
    raise RecordInvalid.new(self)
  end
end

Well I think this is a good place to stop for Part I of this series. In the next post we will dig in to the actual validation process.