Rails Active Record Name Error - ruby-on-rails

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.

Related

Access to model instance up the where chain in Rails

Is it possible to, within the record found through an association, retain access to the related model instance which found it?
Example:
class Person < ApplicationRecord
has_many :assignments
attr_accessor :info_of_the_moment
end
p = Person.first
p.info_of_the_moment = "I don't want this in the db"
assignment = p.assignments.first
assignment.somehow_get_p.info_of_the_moment # or some such magic!
And/or is there a way to "hang on to" the parameters of a scope and have access to them from within the found model instance? Like:
class Person < ApplicationRecord
has_many :assignments
attr_accessor :info_of_the_moment
scope :fun_assignments, -> (info) { where(fun: true) }
end
class Assignment < ApplicationRecord
belongs_to :person
def get_original_info
# When I was found, info was passed into the scope. What was it?
end
end
You can add your own extension methods to an association and those methods can get at the association's owner through proxy_association:
has_many :things do
def m
# Look at proxy_association.owner in here
end
end
So you could say things like:
class Person < ApplicationRecord
has_many :assignments do
def with_info
info = proxy_association.owner.info_of_the_moment
# Then we wave our hands and some magic happens to encode
# `info` into a properly escaped SQL literal that we can
# toss in a `select` call. If you're working with PostgreSQL
# then JSON would be a reasonable first choice if the info
# was, say, a hash.
#
# The `::jsonb` in the `select` call is there to tell everyone
# that the `info_of_the_moment` column is JSON and should be
# decoded as such by ActiveRecord.
encoded_info = ApplicationRecord.connection.quote(info.to_json)
select("assignments.*, #{encoded_info}::jsonb as info_of_the_moment")
end
end
#...
end
p = Person.first
p.info_of_the_moment = { 'some hash' => 'that does', 'not go in' => 'the database' }
assignment = p.assignments.with_info.first
assignment.info_of_the_moment # And out comes the hash but with stringified keys regardless of the original format.
# These will also include the `info_of_the_moment`
p.assignments.where(...).with_info
p.assignments.with_info.where(...)
Things of note:
All the columns in select show up as methods even when they're not part of the table in question.
You can add "extension" methods to an association by including a block with those methods when calling the association's method.
An SQL SELECT can include values that aren't columns, literals work just fine.
What format you use to tunnel your extra information through the association depends on the underlying database.
If the encoded extra information is large then this can get expensive.
This is admittedly a bit kludgey and brittle so I'd agree with you that rethinking your whole approach is a better idea.

undefined method `price_tier' for nil:NilClass

Wondering if someone can help me find this issue. I'm using rails 4, ruby 2, and have spent alot of time trying different accessors, etc and nothing has worked.
The whole plan model:
class Plan < ActiveRecord::Base
has_many :users
end
Some of the user model:
class User < ActiveRecord::Base
...
validate :plan_type_valid
belongs_to :plan
...
def plan_type_valid
if free_ok
# the following line causes error
valid_plans = Plan.where(price_tier: plan.price_tier).pluck(:id)
else
valid_plans = Plan.where(price_tier: plan.price_tier).where.not(stripe_id: 'free').pluck(:id)
end
unless valid_plans.include?(plan.id)
errors.add(:plan_id, 'is invalid')
end
end
end
Here's a pastebin of the whole users controller:
http://pastebin.com/GnXz3R8k
the migration was all messed up because of a superuser issue and it wasn't able to create the extensions for hstore field type.

Can't access foreign key property in Rails

I have two classes - pop_vlans and logical_interfaces defined as follows:
logical_interface.rb
class LogicalInterface < ActiveRecord::Base
has_many :pop_vlans
end
pop_vlans.rb
class PopVlan < ActiveRecord::Base
self.table_name = 'pop_vlans'
belongs_to :logical_interface, :class_name => "LogicalInterface", :foreign_key => "vlan_id"
end
Then in my controller I am trying to access the pop_id column of the related pop_vlans object but I get an undefined error:
logical_interface_controller.rb
def update
if params[:id]
#logical_interface = LogicalInterface.find(params[:id])
#pop_id = #logical_interface.pop_vlan.pop_id # error
end
end
However, I can get the property I want but it requires a few extra lines:
#vlan_id = #logical_interface.vlan_id
#pop_vlan = PopVlan.find(#vlan_id)
#pop_id = #pop_vlan.pop_id
but I'd rather make my scripts a bit more concise (plus, find out why the above doesn't work aswell as it's genuinely annoying me!).
You have define
has_many :pop_vlans
which means you must access it with
#logical_interface = LogicalInterface.find(...)
#logical_interface.pop_vlans # return an array of pop_vlans
# ^
#logical_interface.pop_vlans.map(&:pop_id) # return an array of pop_ids

rails 3.1 inflection problem

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

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