Rails Cannot Find Model with Same Name as Ruby Class

Rails cannot find model with same name as Ruby class

Don't name it Set. That way lies madness.

The deal is that defining the class fails because you're trying to redefine 'Set' which is already defined in the global context.

class Set < ActiveRecord::Base # You are attempting to define a constant 'Set'
# here, but you can't because it already exists

You can put your class in a module, and then you won't get the error because you'll be defining Set within a namespace.

module Custom
class Set < ActiveRecord::Base
end
end

However, every single time you want to use your Set class, you'll have to refer to it as Custom::Set. A lot of Rails magic won't work because it's expecting class names to be defined in the global context. You'll be monkeypatching plugins and gems left and right.

Far easier to just give it a different name.

class CustomSet < ActiveRecord::Base

All the magic works, and no monkeypatching required.

How do I use a model that has the same name as a gem?

You can't. A module and class of the same name cannot exist at the top-level namespace. If you actually did get Rails to load your Stripe module, your app would crash with a type error, complaining that you've tried to change the type of Stripe from module to class.

classes with same names

When you declare classes in a name space, rails expects the files for the MVC to be placed in a folder with the same name as the namespace.

Try placing them in

app/models/workplace/user.rb

app/controllers/workplace/user_controller.rb

app/views/workplace/

Rails associated models with a method of the same name

Firstly, ActiveRecord::Concern can change a lot of behaviour and you've left out a lot of code, most crucially, I don't know where it's being injected, but I can make an educated guess.

For a Concern's methods to be available a given object, it must be include'd in the object's class's body.

If you have access to an instance of the Order object, at any point you can call the balance method:

order = Orders.last         # grab the last order in your database
order.balance # this will call Order#balance

And if you have the Order then you can also get the LineItem:

order.line_items.first.balance    # should call the Concerns:: LineItems::Aggregates#balance

You can open up a Rails console (with rails console) and run the above code to see if it works as you expect. You'll need a working database to get meaningful orders and balances, and you might need to poke around to find a completed order, but Ruby is all about exploration and a REPL is the place to go.

I'd also grep (or ag or ack) the codebase looking for calls to balance maybe doing something like grep -r "(^|\s)\w+\.balance" *, what you want to look for is the word before .balance, that is the receiver of the "balance" message, if that receiver is an Order object then it will call Order#balance and if it is a LineItem object then it will call Concerns:: LineItems::Aggregates#balance instead.

I get the feeling you're not familiar with Ruby's paradigm, and if that's the case then an example might help.

Let's define two simple Ruby objects:

class Doorman
def greet
puts "Good day to you sir!"
end
end

class Bartender
def greet
puts "What are you drinking?"
end
end

Doorman and Bartender both have a greet method, and which is called depends on the object we call greet on.

# Here we instantiate one of each
a_doorman = Doorman.new
a_bartender = Bartender.new

a_doorman.greet # outputs "Good day to you sir!"
a_bartender.greet # outputs "What are you drinking?"

We're still using a method called greet but the receiver is what determines which is called.

Ruby is a "message passing language" and each "method" is not a function but it's a message that is passed to an object and handled by that object.


References

  • How to use concerns in Rails 4
  • http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
  • http://guides.rubyonrails.org/command_line.html#rails-console

ruby modules and classes same name in structure

Bar can't be a module and a class, they are different things.

Change bar.rb to module Bar or change other_bar.rb to class Bar.

Whichever it is, it has to be consistent. You can't change one to the other. The question is which should it be? If Bar is a container for other classes and only has a few global singleton methods? Then it's a module. But if it can be instantiated, then it's a class.

And yes, you can nest classes. This is totally acceptable:

class Bar
class OtherBar
puts "running module Bar with class OtherBar"
end
end

Bar::OtherBar.new # yay!

Modules and Classes can be nested inside either other in any way you see fit.


Edit with some commented examples to help clear this all up:

module Foo

# Foo::A
class A
# simple namespaced class
end

# Foo::B, inherits from Foo::A
class B < A
# inherting from a class in the same namespace
end

# modify Foo::B
class B
# When modifying an existing class you don't need to define the superclass
# again. It will raise an error if you reopen a class and define a different
# superclass. But leaving it off is fine.
end

# nested module Foo::Inner
module Inner

# Foo::Inner::C
class C
# simple more deeply namespaced class
end

# Foo::Inner::D, inherits from Foo::A
class D < A
# inherits from a class in a parent namespace

# works because ruby looks upward in the nesting chain to find missing constants.
end

# Foo::Inner::Foo
class Foo
# simple nested class with the same name as something in a parent namespace

# This is a totally different Foo, because it's in a different namespace
end

# Foo::Inner::E, inherits from Foo::Inner::Foo
class E < Foo
# class inhereting from another class in the same namespace

# Foo::Inner::Foo is "closer" than the global Foo, so that gets found as the superclass
end

# Foo::Inner::F, which mixes in the gloabl module Foo
class F
# the :: constant prefix says to start looking in the global namespace
# so here we include the top level module Foo, and not the "closer" in namespace Foo::Inner::Foo
include ::Foo

# This is an error. This attempts to include the class Foo::Inner::Foo since thats the closest by namespace
# thing that matches the constant Foo. (you can't include classes, only modules)
# You need the :: prefix to grab the global Foo module
include Foo
end

end
end

# Z decalred in the global namespace, which inherits from the deeply nested class Foo::Inner::C
class Z < Foo::Inner::C
# Any class anywhere can inherit from any other class in any namespace.
# Just drill in!
end

# the following 2 declarations at this point would be identical

# This defines a class deep with in a namespace
class Foo::Inner::Foo::Bar < Foo::A
end

# same as above, but reopens each namespace
module Foo
module Inner
class Foo
class Bar < ::Foo::A
end
end
end
end

Accessing a module/class with same name in a different file in ruby on rails

Try

constants = ::Report::Category.constants.collect{|c| c.to_s}

(note :: before Report that causes constant's lookup to start looking from the outmost context)



Related Topics



Leave a reply



Submit