rails models - ruby-on-rails

i have a model named test.rb and when i use #tests=Test.new in my controller i get the following error. Can someone temme how can i resolve this?
"undefined method `new' for Test:Module"

Looks like test is already the name of a module called Test if would seem that you have naming conflict. Try placing your own model in a module ie
module MyModule
class Test < ActiveRecord::Base
end
end
and then calling it like so
#test = MyModule::Test.new

Related

ActiveRecord bug with namespaces or expected behavior?

Rails 4.1.16
Ruby 2.2.7
I have this ActiveRecord model:
class Something::Type < ActiveRecord::Base
When referencing the model like this:
Something::Type.find_by_whatever("test")
I get the following error:
NoMethodError: undefined method `find_by_whatever' for ActiveRecord::AttributeMethods::Serialization::Type:Class
I understand that Ruby constants are broken up, so that Type exists as its own constant, and the autoloader is finding ActiveRecord::AttributeMethods::Serialization::Type first.
However, referencing the namespace in an "absolute" way (prefixing with colons) is supposed to solve the issue, but the result is the same. Any ideas why?
::Something::Type.find_by_whatever("test")
NoMethodError: undefined method `find_by_whatever' for ActiveRecord::AttributeMethods::Serialization::Type:Class
The problem when you define a class with the scope resultion operator is that the module nesting is resolved to the point of definition (the point where you use the module keyword). If you look at the module nesting:
class Something::Type < ActiveRecord::Base
puts Module.nesting.inpsect # [Something::Type]
end
The class not even really nested in the Something module. Which will give you an extremely surprising constant lookup:
module Something
FOO = "test"
end
class Something::Type
puts Foo # gives a uninitialized constant error since its not looking in the Something module
end
Instead you should ALWAYS declare namespaced classes with explicit nesting:
module Something
class Type
puts Module.nesting.inspect # [Something::Type, Something]
puts Foo # test
end
end
Which gives the module nesting [Something::Type, Something] which means that it will properly look up constants in the same Something namespace.
This is something that the old classic autoloader tended to gloss over as it relied on monkeypatching Module#const_missing. Zeitwork does not so do it right.

Rails and RSpec: Testing controllers with the same name in different namespace (module)

I have rails 4.1.16 API application that is tested using RSpec 3.4.0, and I experience problems with testing classes called the same name in a different module.
The structure is:
app/controllers/bar/notifications_controller.rb
class Bar::NotificationsController < ApiController
...
end
and controller with the same name in a different module:
app/controllers/foo/bar/notifications_controller.rb
module Foo
class Bar::NotificationsController < ApiController
...
end
end
The Foo is a new module and does not have tests yet.
After adding it, all the corresponding controller tests for the old Bar::NotificationsController started to fail.
The spec file:
spec/controllers/bar/notifications_controller_spec.rb
require 'spec_helper'
describe Bar::NotificationsController, type: :controller do
...
end
All the tests in that spec file fail with the same error:
RuntimeError:
#controller is nil: make sure you set it in your test's setup method.
The problem does not exist when I change the controller name in the Foo module:
app/controllers/foo/bar/foo_notifications_controller.rb
module Foo
class Bar::FooNotificationsController < ApiController
...
end
end
I already tried adding on top of the spec file require 'bar/notifications_controller' and using the class name as a string describe "Bar::NotificationsController, type: :controller but it did not solve the issue (the same error).
Why is this happening? What is the solution?
I want to believe there is a tiny thing I did not try yet and I don't have to pollute my code and the structure with nonsense names just to make the specs pass.
Many thanks in advance for your help!
In general, I've take to including all namespacing in the class definition. Something like:
app/controllers/foo/bar/notifications_controller.rb
class Foo::Bar::NotificationsController < ApiController
...
end
While, at first glance, this might look the same as:
app/controllers/foo/bar/notifications_controller.rb
module Foo
class Bar::NotificationsController < ApiController
...
end
end
These are, in fact, different. The difference is in how Rails handles autoloading of constants. I won't go into the details here because it's a longer topic and there are good articles/posts out in the web-o-sphere.
You can find good articles on how Rails handles autoloading like this one (or try Googling rails constant loading)
Also, as the article notes, Ruby constant loading operates differently than Rails loading. Good information on Ruby constant loading can be found here (or try Googling ruby constant loading).

Auto-create the containing module of a class

In Rails you can create a model under app/foo/bar.rb, with bar.rb containing:
class Foo::Bar
def some_method
puts "I work fine"
end
end
If you try to do this in a pure ruby app you'd get a NameError: uninitialized constant Foo unless you've already initialized a module Foo.
What is Rails doing that allows it to create classes without first initializing their containing module? Is it possible to import this behavior through something like activesupport, or are we left to implement on our own?
Rails modifies the Class class to include a const_missing method which gets called when an undefined class is used. It then loads things to try and load the requested class.
The implementation of this in ActiveSupport is in lib/active_support/dependencies.rb.
actually model class created is extend to < ActiveRecord::Base

undefined method `new' for Test:Module

Hello I have a problem of conflict of the namespace. I have a model: Test and controller TestsController. server displays an error
undefined method `new' for Test:Module
I read this question rails models
added to the model Test in module UserTest
module UserTest
class Test < ActiveRecord::Base
....
end
end
and added to the controller
class TestsController < ApplicationController
def new
#test = UserTest::Test.new
#test.questions.build
#title = "New test"
end
...
end
server shows an error: uninitialized constant TestsController::UserTest
after reading more I realized that probably need to add require or include a controller. Only I do not understand how to do it. please tell me.
Never rename a model to the same name of the project. You will get a message like this:
undefined method `new' for Example:Module
The project module priority precedes on the call.
The convention in Rails is to convert your Class name in file and your module name in directory. So if you put your UserTest::Test class in test.rb file in your app/model directory, the autoload failed to get your class. Because search on app/model/user_test/test.rb file.
So you can "force" the require in your Controller by adding a require in top of your file. The require if you put your class in your test.rb is : require 'test.rb'
To know how define your require is to think the LOAD_PATH of your application add app/model directory. So all inside can be add directly by requiring the directory name and file name.

Subclassed model results in NameError in development environment but not in test

This is my Action model:
class Action < ActiveRecord::Base
end
class Fold < Action
end
class Check < Action
end
class Call < Action
end
class Bet < Action
end
In another model, I have this
class Deal < ActiveRecord::Base
def Deal.parse_action(action_string)
case action_string
when "folds": Fold.new()
when "checks": Check.new()
when "calls": Call.new()
when "bets": Bet.new()
when "raises": Bet.new()
else nil
end
end
# ...
end
Now, when I test this if this works in my unit tests, everything appears to work. But as soon as I start the web server in development mode, I get this:
NameError (uninitialized constant Deal::Fold):
app/models/deal.rb:115:in `parse_action'
...
Why does it think Fold exists within the namespace Deal? And why does this not happen in the test environment?
It's not saying that Fold exists in the Deal namespace, it's saying that it's looking for the constant Fold and it's currently inside Deal. For example, try this:
class Foo
def test; puts Bar; end
end
Foo.new.test
and you'll get this:
NameError: uninitialized constant Foo::Bar
from (irb):3:in `test'
from (irb):7
from :0
Rails has stuff to auto-load constants for you and I'm guessing the problem is that you don't have the Fold class in its own file. Try putting the Fold class definition into it's own file -- app/models/fold.rb and see if that helps. If so, try putting it back in the action.rb file and then doing something that would cause the Action file to load before you do the case statement, like x = Action right before the case statment. If that works then you need to require "action.rb" in deal.rb because the issue is that your test code is loading action.rb (possibly through some other test) but your production code isn't.
I don't use Rails at work, but I sometimes come across the scenario of a class being known when I'm running tests, but not when I'm running the executable. That happens because I have the requisite "require" statements in my test files for the relevant files, but I hadn't got around to putting the requisite "require" statements in production code.
In Ruby to add a method to a class you have declare like so:
class Deal < ActiveRecord::Base
def self.parse_action(action_string)
case action_string
when "folds": Fold.new
....
That may be the source of your problems as well.
Also (sorry to nit pick) but you don't need the parenthesis on Fold.new. You are able to pass parameters to methods without using parathesis.

Resources