Jared Short
Jared Short

Reputation: 150

How does ActiveRecord handle Relationship CamelCasing

I have a question about rails and how its relationships query builder, specifically how camel case is converted for the related calls.

Relevant Code

class CustomerPlan < ActiveRecord::Base
  attr_accessible :customer_id, :plan_id, :startDate, :user_id

  has_many :planActions
end

class PlanAction < ActiveRecord::Base
  attr_accessible :actionType_id, :customerPlan_id, :notes, :timeSpent

  belongs_to :customerPlan
  belongs_to :actionType
end

The getters and setters work just fine, such as plan_action.actionType.name will correctly pull from the related model. However customer_plan.planActions.each returns the error:

SQLite3::SQLException: no such column: plan_actions.customer_plan_id: 
  SELECT "plan_actions".* 
    FROM "plan_actions"  
    WHERE "plan_actions"."customer_plan_id" = 1

The column is defined in the database as customerPlan_id, was I just wrong to use this? It works for every other call, all my other relationships work fine. Even PlanAction -> CustomerPlan.

I ran through all the docs, and searched about every other source I know of. It would be simple enough to change my columns, I just want to know what's going on here.

Thank you for your time!


A quick fix for this is to just explicitly set the foreign_key.

has_many :planActions, :foreign_key => "customerPlan_id", :class_name => "PlanAction"

Still, I think I am missing some model naming convention somewhere, just can't seem to figure out what.

Upvotes: 2

Views: 139

Answers (2)

Dia Kharrat
Dia Kharrat

Reputation: 6006

The Rails convention for DB column names is to use lowercase letters with words separated by an underscore (e.g. author_id, comments_count, updated_at, etc).

I would highly recommend that you stick to the Rails conventions. This would make your life much easier. To change it to the rails convention, simply create a migration to rename the column to the appropriate style.

However, if you do want to use a custom style for the column name, rails provides the :foreign_key option in the has_many relationship to specify the expected foreign column name:

class CustomerPlan < ActiveRecord::Base
  has_many :plan_actions, :foreign_key => 'customerPlan_id'
end

You can also use the alias_attribute macro to alias the column name, if you'd like to use a different model attribute name than the actual DB column name. But as I mentioned, I would recommend sticking to the rails convention as much as possible. You'll thank me later.

Upvotes: 1

Brad Werth
Brad Werth

Reputation: 17647

Rails has 3 basic naming schemes.

One is for constants, and it is ALL_UPPERCASE_SEPARATED_BY_UNDERSCORES.

One is for Classes and it is AllCamelCaseWithNoUnderscores.

One is for variables and method names, and is all_lowercase_separated_by_underscores.

The reason that it is this way is not just for consistency, but also because it freely converts between them using these methods.

So, to make your posted code more rails-y:

class CustomerPlan < ActiveRecord::Base
  attr_accessible :customer_id, :plan_id, :start_date, :user_id

  has_many :plan_actions
end

class PlanAction < ActiveRecord::Base
  attr_accessible :action_type_id, :customer_plan_id, :notes, :time_spent

  belongs_to :customer_plan
  belongs_to :action_type
end

Upvotes: 0

Related Questions