rails 3.1 inflection problem - ruby-on-rails

I have a Rails 3.1 app with the following 2 models
class Listing < ActiveRecord::Base
has_many :listing_saves
end
class Team < ActiveRecord::Base
has_many :listing_saves
has_many :saved_listings, through: :listing_saves, source: 'listing'
end
The Join model looks like this
class ListingSave < ActiveRecord::Base
belongs_to :team
belongs_to :listing
end
Mow I think that there is an inflection problem because whenever I try to run my tests I get the following error (this is an example of an error and the test that caused it)
it "should return the listing saves associated with the team" do
save = Factory :listing_save, listing: #listing, saver: #user, team: #team
#team.listing_saves.should include save
end
Failures:
1) Team listing_saves associations should return the listing saves associated with the team
Failure/Error: #team.listing_saves.should include save
NameError:
uninitialized constant Team::ListingSafe
# ./spec/models/team_spec.rb:55:in `block (3 levels) in <top (required)>'
as if Rails is singularizing listing_saves into listing_safe
Here are some custom inflectors I have tried (not all at the same time) (none of them work)
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.plural 'saved_listing', 'saved_listings'
inflect.singular 'saved_listings', 'saved_listing'
inflect.plural 'listing_save', 'listing_saves'
inflect.singular 'listing_saves', 'listing_save'
inflect.singular 'listing_safes', 'listing_safe'
inflect.plural 'listing_safe', 'listing_safes'
inflect.irregular 'listing_save', 'listing_saves'
inflect.irregular 'saved_listing', 'saved_listings'
end
What can I do next?
Note: I found the this similar question but the answer doesn't seem to solve my problem
Edit
I followed the answer below so that I now have the following in my config/initializers/inflections.rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'listing_save', 'listing_saves'
end
When I open up a console session and run "listing saves".singularize I get "listing_save" as I would hope. However, it seems that at least part of my application doesn't get it, my tests still fail in the same way as before. (I swear I'm restarting my server and spork before I test/run the application!).
Edit 2
I wrote some tests for inflections in my app:
describe "inflection" do
it "should singularize listing_saves properly" do
"listing_saves".singularize.should == "listing_save"
end
it "should pluralize listing_save properly" do
"listing_save".pluralize.should == "listing_saves"
end
end
Now I have a situation where these tests pass fine, but other tests still fail with the same error I was having before
NameError:
uninitialized constant User::ListingSafe
Same app, same spork instance, same files loaded. Something weird is going on here!??

You need to define an irregular inflection:
# Test your inflections!
> "listing_save".pluralize
=> "listing_saves" # OK!
> "listing_saves".singularize
=> "listing_safe" # Ouch :(
# Make it smarter
ActiveSupport::Inflector.inflections { |i|
i.irregular 'listing_save', 'listing_saves'
}
# Test again
> "listing_saves".singularize
=> "listing_save" # Yay!
Ruby docs:
------------------------ ActiveSupport::Inflector::Inflections#irregular
irregular(singular, plural)
------------------------------------------------------------------------
Specifies a new irregular that applies to both pluralization and
singularization at the same time. This can only be used for
strings, not regular expressions. You simply pass the irregular in
singular and plural form.
Examples:
irregular 'octopus', 'octopi'
irregular 'person', 'people'
Edit:
Some further investigation - and it looks like others have stumbled upon this same problem also (inflections not working as expected with associations). So in the meantime you can set the class name manually:
has_many :listing_saves, :class_name => "ListingSave"
Someone else with the same problem, and an additional inflections tweak. Personally I'd go with the :class_name setting instead though:
Issue with custom inflections in Ruby on Rails 3.0.3

Related

Rspec - unknown attribute error

I followed the Restauranlty tutorial at rubyonrailstutor.com and everything worked perfectly. Now I'm trying to implement the same tests in my project, which has more models with associations between them and I'm getting errors.
I've tried researching this problem, and even came across a few questions on this site - most notably this one and this one.
I have the following models:
class Album < ActiveRecord::Base
belongs_to :artist
validates_presence_of :title
validates_presence_of :no_of_tracks
end
class Artist < ActiveRecord::Base
has_many :albums
end
And I have the following factories:
FactoryGirl.define do
factory :artist do
name "MyString"
image "MyString"
bio "MyString"
end
end
FactoryGirl.define do
factory :album do
title "MyString"
no_of_tracks 0
artist
end
end
Apart from following the Restaurantly tutorial, this is my first time testing so I also looked at this guide for setting up factory girl for models with associations.
My test is:
describe Album do
subject(:album) { FactoryGirl.build :album, title: nil, artist: nil,
no_of_tracks: nil }
it { expect(album.valid?).to be_false }
end
But when I run it it fails with the error: can't write unknown attribute artist_id.
The questions I mentioned above suggested that perhaps my database has not been properly migrated but I've run both
bundle exec rake db:migrate RAILS_ENV=test
and
bundle exec rake db:test:prepare
to no avail. As I said, I'm very, very new to testing so if anyone could point me in the right direction I'd be grateful.
Everything looks fine.
Do you really have a column artist_id in your albums table ?
I suspect that albums table in your database does not have artist_id foregin key.

Uninitialized constant in view

I have two models:
Post:
class Post < ActiveRecord::Base
has_many :exes
end
Exe:
class Exe < ActiveRecord::Base
belongs_to :post
end
What I am getting in my view on http://localhost:3000/posts/index is:
NameError in Posts#index
uninitialized constant Post::Ex
It says just Ex for some reason.
The code of line ruby is complaining on is <% post.exes.each do |exe| %> which looks right to me.
So I don't really know why this is happening. If have also checked the following as i thought this might be the reason but no:
2.0.0-p247 :004 > ActiveSupport::Inflector.pluralize('Exe')
=> "Exes"
2.0.0-p247 :005 > ActiveSupport::Inflector.singularize('Exe')
=> "Exe"
Thanks in advance!
Your problem is that ActiveSupport::Inflector is assuming that a word that ends in 'xes' in the plural form must end in 'x' in the singular form. See here for help on customizing pluralizations.
Update: Somehow I missed the last part of your question. You said you tried:
> ActiveSupport::Inflector.singularize('Exe')
but did you try:
> ActiveSupport::Inflector.singularize('Exes')
Define the inflector for this particular string in your project's inflections initializer:
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'Exe', 'Exes'
end
Remember that you'll need to restart your server before changes will take effect.

Rails Active Record Name Error

I'm facing the following error:
NameError at
uninitialized constant XController::Sheep
at this line
server = Sheep.find_by_id(id)
This is my setup:
Under models/sheep.rb
class Sheep < ActiveRecord::Base
has_many :kids
end
Under models/kid.rb
class Kid < ActiveRecord::Base
belongs_to :sheep # I tried adding , :class_name => 'Sheep' didn't do anything
end
Under config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.uncountable 'sheep'
end
The table name is actually sheep I checked
What else should I check?
EDIT:
In the controller controllers/farm.rb I make two calls:
#kid = Kid.find_by_id params[:id]
#sheep = Sheep.find_by_id(id) # works only when adding :: as in the answer
You can try accessing this model's name with double colon:
server = Sheep.find_by_id(id)
# become
server = ::Sheep.find_by_id(id)
^^
Then it should work.
I don't have enough infos yet to tell why it is not working without the colons, but my intuition tells me that XController::Sheep suggests you have a problem in you Controller's names.

Is there a Lint for ActiveRecord?

Rubyists, particularly Railsers, know all about ActiveModel::Lint, which is a handy way to ensure that you haven't cocked up when writing your ActiveModel subclass, and saves hours of head-scratching. I use it all the time for table-less models in Rails projects.
But I spend a lot of time hunting down errors with my usage of ActiveRecord - particularly with double-sided associations. For example
# app/models/blog.rb
class Blog < ActiveRecord::Base
has_many :posts # so far so good...
end
# app/models/post.rb
class Post < ActiveRecord::Base
has_one :blog # incorrect - should be belongs_to
end
That example is somewhat contrived, as nobody's that silly. But what if Blog actually has a post_id column? Exceptions would not be raised where expected.
I'd like to be able to write a test for Blog like this
# test/unit/blog_test.rb
require 'test/test_helper'
class BlogTest < ActiveSupport::TestCase
include ActiveRecord::Lint
end
...and the test output should say something like Blog :has_many :posts, but Post does not :belong_to :blog!. It would need to reflect on the associations, dealing with table-names, foreign-keys, etc, and considering :through models on the way. I know that proper unit tests will detect these issues anyway, but generally as side-effects of other tests.
Does anyone know of a project which does this? (I'm only interested in ActiveRecord >= 3.1). All I could find was active_record_lint, which doesn't really do this at all.
Additionally, it would be great if all the existing fixtures could be tested automatically, to make sure that those pesky associations are set up. I usually just do
test "fixtures" do
Post.all.each { |p| assert p.valid? "Fixture is broken! #{p.inspect}" }
end
but there's surely a more elegant way.
A tool like this would be useful, but you should be testing these things explicitly anyway. This will uncover problems like this immediately. For instance, a typical unit test:
def test_defaults
blog = Blog.create(
:title => 'Example Blog'
)
assert blog.valid?
assert_equal [ ], blog.errors.full_messages
assert !blog.new_record?
assert_equal 0, blog.posts.count
end
For your post:
def test_defaults
blog = Blog.create(
:title => 'Example Blog'
)
post = Post.create(
:blog => blog,
:content => 'Blogging blog bloggers blogged blogs'
)
assert post.valid?
assert_equal [ ], post.errors.full_messages
assert !post.new_record?
assert_equal blog.id, post.blog_id
assert_equal 1, blog.posts.count
end
Those are the long form versions of some helper methods that I usually use.
If you don't exercise the relationships, you're not testing them and you've got a problem with your test coverage. If you exercise a bad relationship it will show up as an error.

Getting a NameError with ActiveRecord and relationships

I've run into a problem when using a one to many relationship. I want to have each Series have one Publisher and that one Publisher has many Series.
This is my Publisher model:
class Publisher < ActiveRecord::Base
validates_presence_of :name
has_many :series
end
This is my Serie model:
class Serie < ActiveRecord::Base
belongs_to :publisher
end
This is the failing test:
test "a publisher should have a list of series" do
#publisher = Publisher.new :name => "Standaard Uitgeverij"
#series = [ Serie.new(:name => "De avonturen van Urbanus", :publisher => #publisher),
Serie.new(:name => "Suske en Wiske", :publisher => #publisher) ]
assert_equal #series, #publisher.series
end
The test fails on the last line with NameError: uninitialized constant Publisher::Series.
I tried to save the publisher and the series, but this did not work. I tried it with only one serie, but this gives the same error.
Since I'm just starting out with Rails and Ruby, I am at a loss here. What am I doing wrong?
To address your actual question as mentioned in your comment (how can I name my model "Series"?), you need to make the Rails' Inflector aware of this exception to its default pluralization rules.
Add the following to config/environment.rb:
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable 'series'
end
This will let you name your model as Series. You can test that it's worked using script/console:
>> "series".pluralize #=> "series"
>> "series".singularize #=> "series"
—I have to say that I've just tried using The Pluralizer and it would appear that Rails has knowledge of how to handle the word series built-in. Try it for yourself.
I believe John's answer is the best one.
You can also directly specify the class name in the has_many declaration
has_many :series, :class_name => 'Serie'
Your has_many relationship name is fine, but your model name is wrong.
As the singular and plural of series are both series, you need to rename your model from Serie to Series. After that, everything should be fine.

Resources