Archive for the ‘active-record’ tag
Active Record: Nested attributes
I recently learnt about quite a neat feature of Active Record called nested attributes which allows you to save attributes on associated records of a parent model.
It’s been quite useful for us as we have a few pages in our application where the user is able to update models like this.
We would typically end up with parameters coming into the controller like this:
class FoosController < ApplicationController def update # params = { :id => "1", :foo => { :baz => "new_baz", :bar_attributes => { :value => "something" } } } Foo.update_instance(params[:id], params[:foo]) ... end end
Our original implementation of ‘update_instance’ looked like this:
class Foo < ActiveRecord::Base has_one :bar class << self def update_instance(id, attributes_to_update) instance = Foo.find(id) instance.attributes = attributes_to_update instance end end end
Unfortunately when we execute that code the ‘bar’ association gets completely removed because we didn’t specify the id of ‘bar’ when we were updating the attributes.
We need to change the code slightly to make sure it doesn’t do that:
class Foo < ActiveRecord::Base has_one :bar class << self def update_instance(id, attributes_to_update) instance = Foo.find(id) attributes_to_update[:bar_attributes][:id] = instance.bar.id instance.attributes = attributes_to_update instance end end end
It now works as we’d expect.
There’s other cool stuff that you can do with nested attributes described on the documentation page if you have ‘has_many’ associations but for now we’re just using the simpler ‘has_one’.
Ruby: Getting Active Record validation errors twice
I managed to create an interesting problem for myself while playing around with some code whereby I was ending up with validation errors appearing twice every time I called ‘valid?’ on a specific model.
I figured I was probably doing something stupid and in fact a few replies by Aaron Baldwin on a mailing list thread on ‘rubyonrails-talk’ helped explain exactly what I’d done:
Are you calling require ‘employee’ anywhere? If so you are likely
causing the model to load twice which causes duplicate errors because
the validates_presence_of method gets called twice.
I’d put the following code into a controller elsewhere somewhat unnecessarily since it didn’t seem to be picking up the location of my model at the time:
code_submissions_controller.rb
require 'models/code_submission' class CodeSubmissionsController < ApplicationController def new CodeSubmission.new end end
require doesn’t load a file if it’s already been included but Aaron points out why it does on this occasion:
You are right that “require” will only load the file once. But if you load the class another way calling “require” will load it again.
As I understand it that controller code would also implicitly require ‘code_submission’ by the convention of inserting an underscore between the ‘CodeSubmission’ constant’s names.
We therefore effectively have the following two requires:
require 'code_submission' require 'models/code_submission'
Which explain how the file gets loaded twice and therefore why the validation method fires twice and therefore creates two errors!