Tag: rails


Non-ActiveRecord::Base serialized has_many attributes in a nested form

June 15th, 2011 — 3:07am

Per my previous post, I’m trying to be better about recording “Duh” / “Aha” moments in my experiments with Rails to 1) improve my learning / general consumer-of-open-source-software habits, and 2) in hopes that I don’t make similar same silly mistakes again.

This post: fields_for with a serialized has_many relationship

I’ve used plenty of nested forms recently, but always (and now, in retrospect, not always necessarily) with ActiveRecord-based has_many relationships.

Today, I was adding a new attribute to an existing model, and wanted to add some attributes that would simply be attached to the model via a serialized field, rather than any sort of join (similar to the setup in this post).

I wanted to store a set of BillItems on each User, but since they would be fairly isolated from anything else in the database and be tied strictly to each User, I decided to just attach it to each User.

And because each User could theoretically have many BillItems, we’d want to ensure :bill_items was serialized as an Array.

I was finding, though, frustratingly, that the following form was being generated incorrectly – only a single bill_item field was represented in the form, and even when sanity checking by iterating over bill_item records manually, the field markup was missing the indices necessary for the form to recognize each field as a separate form parameter. So when the template looked like this:

The output looked (sadly) like this:

What the docs missed out on saying (under One-to-many) is that: rather than the projects_attributes= attributes writer method just being 1) recommended, 2) worth considering, and 3) available to be replaced by a accepts_nested_attributes_for if :projects were already an association on the model, it’s actually required for fields_for to correctly nest the fields.

And, of course, :bill_items not being a proper association, I wasn’t able to use the standard accepts_nested_attributes_for helper and ran afoul of this. With the correct *_attributes method defined, the form finally displays perfectly, so that bill_items are passed through correctly, as an Array:


Lesson learned, and change committed.

Comment » | techy

Digging into Frameworks and Recording “Duh” Moments

June 15th, 2011 — 2:30am

I’ve been working closely with our intern Cory, and have now been put in the situation of having to explain why Rails is doing X or not doing Y more in the last couple weeks than the whole of the last several months. (It’s also worthwhile saying that it’s incredibly nice having someone to bounce thoughts off of again – no more coding in vacuum.) After each time one or both of us gets tripped up on something, I’m reminded to store that bit of knowledge somewhere useful.

I / we / anyone (me) serious about improving as a programmer needs to dive in and really understand how things are put together. With that goal in mind, I’ve got a couple resolutions to declare:

1. I’m going to be more diligent about reading Rails code – I’ve done my fair share of poking, but I’m going to be much more stringent about reading documentation and code to really understand what’s going on.

2. I’m going to stop lurking / being an isolationist on Github and be more proactive about submitting patches, which I’ve been improving at over the last few months (especially for documentation, as I encounter things that end up being “duh” moments).

First up, redirect_to:

redirect_to is an awfully common method in controllers, and most people use it without thinking or looking too deeply at the internals. Cory tried to be a little more correct with one particular redirect_to, though, by adding :status => :unauthorized, and we found that the controller, in fact, no longer redirected the user. Instead, it displayed a “You are being redirected.” message and simply sat there.

Digging into the source shows us that redirect_to works by returning a HTTP response status of 302 to the browser (of course) – which then knows to look up response’s location and fetch that instead.

So when a 4xx response code is passed in, it overrides the default 3xx redirect status code and the browser simply displays the response_body and (seemingly) chokes. I’ve committed a change on the docrails Github project to clarify this point for anyone staring at the documentation in the future.

More up in a second blog post!

1 comment » | techy

Learning something new every day

December 2nd, 2009 — 3:15am

After staring at a rake task for twenty minutes and manually testing some cases in a console, I’ve got some interesting larnin’s about ActiveRecord::Base.find and what it does with an options hash.

Background
There are typically two ways to provide conditions for a database search via ActiveRecord. The first is find, which looks like this most of the time: User.find(:all, :conditions => {:first_name => 'Bob', :last_name => 'Smith'}, :limit => 5). find takes two arguments: {:all, :first, :last}, and an options hash (more here).

Or taking advantage of existing relationships, which basically ORM-magic away a one-to-many foreign-key relationship between tables, e.g. some_user.files would return an array of some_user‘s File objects. So on and so forth.

And a third way, which I like and think cleans things up really nicely but is apparently not relevant to this bit of learning, is using named scopes (more references) – essentially, a way to wrap up any part of that options hash into what looks like a method on the model itself. An example involving a female named scope on our beloved Usermodel.

class User < ActiveRecord::Base
  named_scope :female, :conditions => {:gender => 'female'}
end

This allows you to not only get all female Users by calling User.female, but also allows combining of named scopes and the find method to minimize repetition and narrow the scope of a query. For example:
User.female.find(:all, :conditions => {:first_name => 'Christine'})

But wait!
In a script I was working on recently, I needed to loop through an array, and look something up at each step:

args = { :select => 'some_attr_id', :limit => 5 }
user_array.each do |user|
  if condition
    files = user.files.published.find(:all, args)
  else
    files = user.files.unpublished.find(:all, args)
  end
  ... < do stuff with the files >
end

Interestingly enough, as args passed through the loop each time, it picked up the parameters added by the user-files relationship! Meaning, the first time through the loop with User 1, the args hash looked like this:
{:include=>nil, :readonly=>nil,
:conditions=>"`files`.user_id = 1",
:joins=>nil, :select=>"some_attr_id", :group=>nil,
:offset=>nil, :limit=>5, :having=>nil, :order=>"files.created_at DESC"}

… which makes all sorts of sense, considering a query like user.files.published would just be a search across some files table with user_id and a published conditions, but how irritating that the args hash was 1) mutable at all, and 2) modified by being passed into the ActiveRecord query!,

1 comment » | techy

Back to top