I tried creating a model called "class" (as in a graduating class of students), and encountered all kinds of problems. What are some other words or class names to avoid in Rails?
Some links I've found:
http://juicebar.wordpress.com/2007/05/30/reserved-words-in-rails/
http://railsforum.com/viewtopic.php?id=22242
This page has a very long list of words not to use:
https://reservedwords.herokuapp.com/words
Because 'class' comes up very commonly as a name with metaprogamming, I think the accepted ruby alternative is 'klass'. This is obviously a different context from your graduating class situation, but maybe still helpful.
You've got most of them there. Obviously, you also need to avoid the Ruby keywords:
alias and BEGIN begin break case class def defined
do else elsif END end ensure false for if
in module next nil not or redo rescue retry
return self super then true undef unless until when
while yield
(from http://www.zenspider.com/Languages/Ruby/QuickRef.html#4).
Also, don't name a model Transaction (but the generator warns about that!).
Class is a built-in ruby class. It is what classes is an instance of.
class Foo
end
puts Foo.class
# => Class
Overriding that blows up the entire object structure in Ruby.
Related
Why isn't the Ruby interpreter throwing a NameError in this instance here?
class OrangeTurtle
self.table_name = 'turtles'
end
Filename: orange_turtles.rb
This answer might sound like a cop out, but it doesn't throw an error because Ruby doesn't care even the slightest what your filenames are called.
e.g. in file asdfasdf.no_rb_ending_here we can have
#!/usr/bin/env ruby
module Something
class Test
def test
puts 'test'
end
end
end
class SomethingElse
def otherThings
puts 'haha'
end
end
Then to make things even weirder, I can have a separate file that modifies (monkey patches) the classes defined in that file.
in more_stuff.rb
#!/usr/bin/env ruby
require_relative 'asdfasdf.no_rb_ending_here'
module Something
class Test
def test2
test()
puts '2'
end
end
end
class SomethingElse
def moreThings
otherThings()
puts 'MOAR'
end
end
Something::Test.new.test2()
# test
# 2
SomethingElse.new.moreThings()
# haha
# MOAR
Ruby is pretty cool - you don't get errors for things that don't NEED to cause an error.
The name error, or uninitialized constant error only appears in Rails. The reason for that is, that active record (which is also a general design pattern) is mapping the tables in the database with the models (or with objects in general).
Active Record can only make that connection via the naming conventions for files and the classes.
As mentioned in the other answer, pure ruby doesn't need to comply with these conventions. However, it is a general rule to name the files like the classes they contain to have better organised code.
Developing in Rails 5.2.2.1. I want to define a "global" rescue handler for my model, so that I can catch NoMethodError and take appropriate action. I find that controllers can do this with rescue_from, but models cannot. Knowing that the Rails Developers are smart people ;) I figure there must be some Good Reason for this, but I'm still frustrated. Googling around, and I can't even find any examples of people asking how to do this, and other people either telling them how, or why they can't, or why they shouldn't want to. Maybe it's because rescue handlers can't return a value to the original caller?
Here's what I'm trying to do: I need to refactor my app so that what used to be a single model is now split into two (let's call them Orig and New). Briefly, I want to make it so that when an attribute getter method (say) is called against an Orig object, if that attribute has moved to New, then I can catch this error and call new.getter instead (understanding that Orig now belongs_to a New). This solution is inspired by my experience doing just this sort of thing with Perl5's AUTOLOAD feature.
Any ideas of how to get this done are much appreciated. Maybe I just have to define getters/setters for all the moved attributes individually.
Overide method_missing :) !?
You could try overriding the method_missing method. This could potentially cause confusing bugs, but overriding that method is definitely used to great effect in at least one gem that i know of.
I didn't want to call the class new because it is a reserved keyword and can be confusing. So I changed the class name to Upgraded.
This should get you started.
class Upgraded
def getter
puts "Congrats, it gets!"
end
end
class Original
def initialize
#new_instance = Upgraded.new
end
def method_missing(message, *args, &block)
if message == :attribute_getter
#new_instance.send(:getter, *args, &block)
else
super
end
end
def respond_to_missing?(method_name, *args)
method_name == :attribute_getter or super
end
end
c = Original.new
c.attribute_getter
You will have to change names of the getter and setter methods. Because you have a belongs_to association you can just use that.
Or you could try just using delegate_to
like #mu_is_too_short suggests, you could try something like this?
class Original < ApplicationRecord
belongs_to :upgraded
delegate :getter_method, :to => :upgraded
end
class Upgraded < ApplicationRecord
def getter_method
end
end
Apparently what I needed to know is the word "delegation". It seems there are a variety of ways to do this kind of thing in Ruby, and Rails, and I should have expected that Ruby's way of doing it would be cleaner, more elegant, and more evolved than Perl5. In particular, recent versions of Rails provide "delegate_missing_to", which appears to be precisely what I need for this use case.
Rails often has special keywords you can insert into a model that gives it special features. Some examples are acts_as_taggable or has_attached_file. How do I do that kind of Voodoo? I want to create a special option for subscriptions, and give models the ability to be subscribed to, for a RefineryCMS engine/extension. I don't know how to do that kind of Rails magic yet, and I didn't see a relevant Rails guide for it.
Those are actually instance methods on the "Class" class. In Ruby, when you're inside a class definition block, self becomes that class. Since parentheses are optional in method invocations, you can make them look a lot like keyword declarations. So you can do
class Class
def subscribable
define_method :subscribe do
...
end
end
end
class Thing
subscribable
end
Thing.new.subscribe
I am encountering a strange bug in my code. I have a rails application with the following two files in the lib:
lib/module_one/module_two/class_one.rb
module ModuleOne
module Moduletwo
class ClassOne
class << self
def test
puts 'Class one'
ClassTwo.test
end
end
end
end
end
and
lib/module_one/module_two/class_two.rb
module ModuleOne
module ModuleTwo
class ClassTwo
def self.test
puts 'Class two'
end
end
end
end
Now my problem is, that when I go into the console and write:
ModuleOne::ModuleTwo::ClassOne.test
it throws the following: NameError: uninitialized constant ClassTwo
The strange thing is, that the problem seems to be connected to the use of class << self instead of self.method. If I change the class_one.rb file like this it works!:
module ModuleOne
module ModuleTwo
class ClassOne
def self.test
puts 'Class one'
ClassTwo.test
end
end
end
end
Im loading the files in application.rb like this:
config.autoload_paths += %W(#{config.root}/lib)
Is this a bug in rails, or is it just me getting something all wrong?
Im using rails 3.1.3 btw
Constant lookup
So first off, the basic process for constant resolution is that ruby first searches the lexical scope of the receiver (the class or module enclosing the reference) for ClassTwo and when it can't find it, it goes up a level (Module.nesting returns this search path) and so on. In your case that means looking for ModuleOne::ModuleTwo::ClassOne:ClassTwo, then ModuleOne::ModuleTwo::ClassTwo, then ModuleOne::ClassTwo and so on.
If that fails the ruby looks in the inheritance hierarchy of the enclosing class/module (e.g. has the superclass of ClassOne defined something. The ancestors method on module returns this search path. Lastly, the top level constants are searched.
Rails autoloading
Back to rails's magic loading. Here a const_missing hook is added by rails that is called when ruby can't find the class, which basically tries to replicate this search logic, seeing at each step whether a file could have been loaded which would contain the missing constant.
Ideally ruby would pass the search path (i.e. the nesting) to search through, but unfortunately it doesn't: when you reference ClassTwo, const_missing gets called with just 'ClassTwo'.
Rails guesses the nesting by prepending that with the name of the class on which const_missing is being called (i.e. the class enclosing the access to the constant). For example, in your second example it ends up with ModuleOne::ModuleTwo::ClassOne::ClassTwo. You can see this easily enough by defining const_missing to log what it's called with
class Object
def self.const_missing missing_name
puts "qualified name is #{self.name}::#{missing_name}"
super
end
end
Rails then strips off 'ClassOne' and tries ModuleOne::ModuleTwo::ClassTwo and so on up the chain.
So why does class << self make a difference? If you repeat your first case with the const_missing logging you'd see that the logged qualified name is now just ::ClassTwo. const_missing is now being called on ClassOne's metaclass, and because class << self hasn't been assigned to a constant, it has no name and thus rails' attempt to fudge the nesting doesn't work.
This opens the door to a horrible workaround:
module ModuleOne
module ModuleTwo
class ClassOne
class << self
def test
puts 'Class one'
ClassTwo.test
end
end
FOO = class << self; self; end
end
end
end
Because the class that const_missing gets called on now has a name (ModuleOne::ModuleTwo::ClassOne::FOO) rails' workaround now works.
Dave's workaround works I think because const_missing gets called on ModuleOne::ModuleTwo::ClassOne rather than the anonymous eigenclass/metaclass.
The real fix would be for ruby to pass const_missing a nesting. There is a bug logged against ruby to this effect although it has been open for a long time. So yes, this could be considered a bug in the magic loading stuff (there are other edge cases) but the underlying reason is a weakness in the ruby api that forces the use of brittle workarounds.
(Only a partial answer, but need formatting.)
It's because of how class << self works.
For example, if you change it to:
class << self
def test
self::ClassTwo.test
end
end
it works fine.
Edit; too long for reasonable comment.
I'm poking around a bit... On an intuitive level it makes sense to me, I'm just not sure why yet. Don't know if I knew a real reason once, or if I'm just making it up.
I'm not sure why self seems to refer to the module, though; the "Programming Ruby 1.9" book doesn't go in to enough depth on the class << semantics. I'll tweet something and refer to this question and someone smarter will create a real answer.
I have some inherited code that I am modifying. However, I am seeing something strange(to me).
I see some code like this:
::User.find_by_email(params[:user][:email]).update_attributes(:mag => 1)
I have never seen something like this(I am new to Ruby on Rails). What does this do and why doesn't my User.find_by_email(params[:user][:email]).update_attributes(:mag => 1) work? The error says something about the User constant.
I am using Rails 2.3.5 if that helps.
:: is a scope resolution operator, it effectively means "in the namespace", so ActiveRecord::Base means "Base, in the namespace of ActiveRecord"
A constant being resolved outside of any namespace means exactly what it sounds like - a constant not in any namespace at all.
It's used in places where code may be ambiguous without it:
module Document
class Table # Represents a data table
def setup
Table # Refers to the Document::Table class
::Table # Refers to the furniture class
end
end
end
class Table # Represents furniture
end
It makes sure to load the User model in the global namespace.
Imagine you have a global User model and another User model in your current module (Foo::User). By Calling ::User you make sure to get the global one.
Ruby uses (among other things) lexical scoping to find constant names. For example, if you have this code:
module Foo
class Bar
end
def self.get_bar
Bar.new
end
end
class Bar
end
The Foo.get_bar returns an instance of Foo::Bar. But if we put :: in front of a constant name, it forces Ruby to only look in the top level for the constant. So ::Bar always refers the top-level Bar class.
You will run into situations in Ruby where the way your code is being run will force you to use these 'absolute' constant references to get to the class you want.
You might find a lead here: What is Ruby's double-colon `::`?
The "::" operator is used to access Classes inside modules. That way you can also indirectly access methods. Example:
module Mathematics
class Adder
def Adder.add(operand_one, operand_two)
return operand_one + operand_two
end
end
end
You access this way:
puts “2 + 3 = “ + Mathematics::Adder.add(2, 3).to_s