ruby-on-railsuninitialized-constant

Rails 3.2, nested resource, uninitialized constant


I'm having a problem with Rails 3.2.1, a nested resource keeps complaining about an uninitialized constant, I can't figure out why because to me it seems I've done the same as with a different model where this did work. At some point I thought I might be using a reserved word somewhere, but changing the model names didn't help...

Error:

uninitialized constant Brand::Series
Extracted source (around line #11):

8: </article>
9: 
10: 
11: <% @series.each do |serie| %>
12:     <article class='serie_block'>
13:         <%= serie.name %>
14:     </article>

brand.rb

class Brand < ActiveRecord::Base
   has_many :series, :order => "name, id ASC", :dependent => :destroy
end

serie.rb

class Serie < ActiveRecord::Base
    belongs_to :brand
end

brands_controller.rb

def show
  @brand = Brand.find(params[:id])
  @series = @brand.series
end

brands/show.html.erb

<% @series.each do |serie| %>
 <article class='serie_block'>
    <%= serie.name %>
 </article>
<% end %>

I get the same "uninitialized constant Brand::Series" error when I try to create a new serie, but then it refers to "app/controllers/series_controller.rb:21:in `new'", which is this line "@serie = @brand.series.build".

series_controller.rb

# GET /Series/new
# GET /Series/new.json
def new
    @brand = Brand.find(params[:brand_id])
    @serie = @brand.series.build

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @serie }
    end
end

Now the strange thing is that the relation seems to work, Rails is not complaining about "brands" not having a "series" method. But the actual creation of the series object seems to fail :s


Solution

  • In your has_many relation in Brand you use a symbol, representing the pluralized name of your model (as it should be). Rails now needs to find the proper model class from that symbol. To do that, it roughly does the following:

    relation_name = :series # => :series
    class_name = relation_name.singularize.classify # => "Series"
    class_object = class_name.constantize # in the context of the Brand class: => Brand::Series
    

    So the culprit lies in Rails singularize method not being able to get the "proper" singular form of series. If everything would have worked out as you expected it did, class_name would have been "Serie" (notice the missing s at the end).

    Lucky you, you can tell rails to use a specified class name for the relation. So just change your Brand class to this and you will be just fine:

    class Brand < ActiveRecord::Base
      has_many :series, :class_name => "Serie", :order => "name, id ASC", :dependent => :destroy
    end