I'm new to Ruby and recently ran into an issue comparing to values when creating a Ruby on Rails application. In a controller I had the following statement that always returned false:
if (user.id != params[:id])
The problem was the user.id (which is an Active Record) is an integer and params[:id] is a string. It took me a while to figure this out and I finally changed it to:
if (user.id != params[:id].to_i)
Now the statement works as expected.
To avoid this error in the future is there a way to "compile" or get Ruby to warn you if you try to compare 2 different types? Some other issues I've ran into that I would like to "compile check" are:
Warn me if I create a variable but don't use it. To help check for typos in variable names.
Make sure a method exists in a Class so I can avoid method name typos and also to help refactoring, for example if I rename a method.
I'm currently using Ruby 1.8.6-27 RC2 with Rails 2.3.2 and RadRails IDE on Windows.
Test first, then code. If you write tests that cover all branches of your application, you get the assurance that your code both runs and produces correct results.
EDIT: I should point out that the ability to compare two types, not depend on method names until the last second, etc. are core features of Ruby.
You don't call a method so much as you send a message to an object. The object is then responsible for figuring out how to handle the method. In Rails this is used to access DB columns in ActiveRecord. There are no methods for the columns until a message with the column name is sent to the object.
Static typing in Ruby goes against the duck typing system. One can often get polymorphism for free without worrying about complex inheritance/interface schemes.
I suggest embracing these features and compensate for the uncertainty through testing
Ruby doesn't allow you to redefine the == operator for Object. In ruby 1.8 you can't, Ruby 1.9 was supposed to do but I haven't been able to get my script working for core classes. It works well for custom defined objects.
class Object
alias :equal_without_warning :==
def ==(object)
unless self.class == object.class
warn("Comparing `#{self.class}' with `#{object.class}'")
end
equal_without_warning(object)
end
end
Assuming I didn't do some stupid coding error, the answer is NO: you can't check whether you are comparing different type of objects.
Also, I would say you don't. Actually Ruby isn't designed to work in this way, this is more a java approach rather than Ruby style.
Ruby isn't supposed to be safe. It lets you compare any two objects, and that's where much of its power comes from. Rails wouldn't be possible without such dynamic design.
Even a compiled language such as Java or C won't stop you from doing == on two objects. As Ben said, it's best to test first. Inspect the structures you're working with. One way to get information about a Ruby object is to use:
puts object.class
In general, the best way (I know of) to avoid this type of issue for dynamic/scripting languages is to move "logic" to methods/commands and write unit tests for them. Basically, anything that can fail should be tested. The code on the page should be dumb logic... rather than display only those items that meet a certain criteria, it should display all items, and get that list of items from a method that only returns the ones that should be displayed.
Two things I'd suggest:
One: Read up on IRB (or script/console for rails). A common development practice in dynamic languages is to try out snippets of code inside a "live" interpreter (like IRB or the rails console). This practice goes back to the earliest dynamic languages like Smalltalk and Lisp. Ruby-debug is also really useful for troubleshooting problems and would have been a really easy way to figure out the error in your example.
Two: Read up on "Duck Typing". "Types" and variables work a little bit differently in Ruby than many folks expect them to. As I understand it, a variable like user.id doesn't have a "type". The value pointed to by user.id does have a type, but the variable itself doesn't. I believe that's part of why there's no tool that would have told you what your error was in advance of running the program. Comparing those two variables isn't an error because the variables don't have a type. user.id was pointing to an integer at that point in your program, but it would be perfectly legal to assign user.id to point to a string, at which point that comparison would have made a lot more sense. :-)
The best solution I found was a IDE that did on-the-fly syntax checking, such as RubyMine. I'm not sure if it would have solved my original problem but it has helped me find and fix several other syntax and compile errors. Thank you everyone for your suggestions.
Related
I have a Rails4 application to which I want to add a model named 'Parameters' It's a good choice in terms of the models purpose, but I worry that it is also a common programming term.
What is the best practice (individual steps) to ensure that:
Parameters
parameter.thing
... will not conflict with a reserved word in Ruby, Rails, or my particular Gem list?
Ruby has a concept of open classes. That said, when the class MyClass is defined somewhere, it’s perfectly valid to have the following in your code:
class MyClass
def another_method
# do something useful
end
end
That said, there is no “reflection-like” mechanism for this action, since it is how Ruby is intended to work.
One might build the complicated logic like this:
run the application without new Parameters class loaded;
call $defined = const_get('Parameters') || true rescue false;
use $defined global (it’s made global here for the sake of an example) to determine whether the name is free.
or:
use TracePoint#new(:class) on Parameters to detect whether only yours was loaded.
or
use ObjectSpace#each to detect other classes.
or even
parse sources.
But I would not go with any of solutions above. Just call your class MyAppParameters and live with this name.
An IDE like RubyMine should warn you by coloring the text whenever you use a reserved word, but for people like me who use glorified text editors, you can always check this list of Rails related reserved words when you're not sure.
I am using Ruby on Rails 3.1 and I would like to know how, when and why I should use one of the following code rather than another on internationalizing my application (I18n gem):
t(:test_key)
t('test_key')
t('.test_key')
That is, what is the "subtle" difference between using t(:test_key), t('test_key') and t('.test_key')? What are best practices about this issue?
I think first two are equivalent and you just refer to main key in your translations, fo example
t('hello_world')
# t(:hello_world) is an equivalent
would reffer to
en:
hello_world: "Hello world"
However if you use dot notation, its called lazy lookup
and it will look deeper in your translation structure based on controller/action notation
So if you use this inside users/index template
t('.hello_world')
it will be resolved to
pl:
users:
index:
hello_world: "Witaj świecie"
You'll find more about internalization in Rails Guides
I guess it's a but up to you to decide when you actually want to use the different ones, but I'd prefer to use lazy lookup as much as possible in my views, unless you need to translate some generic component whose keys does not live in the scope of your view.
The reason why I prefer the lazy lookup is that it makes the code look cleaner, and as long as you're familiar with how the i18n gem works, you shouldn't have any trouble knowing where to look for the keys.
On the other hand, if you have such components, they should really live in a partial, a cell or something similar.
One thing worth mentioning abouth the non-lazy ones, are that you can provide them with a scope for where to look for the key in question. Again, it's up to you whether you like t('foo.bar.baz.test_key') or t(:test_key, :scope => 'foo.bar.baz').
It also takes a bunch of other options, but all of this is neatly documented in the rails guide, so I won't explain it further here.
I am using Ruby on Rails 3.0.7 and I would like to know, regarding performance matters, what are differences between the User.find(<id>) method and the User.where(:id => <id>) method.
Under the hood, find does more or less what you're describing with your where. You can find the details in this post. That being said, if you're looking to grab a single record by id, then you might want to use find_one. That's what find winds up doing when you call it with a single argument of an id, but you'll skip past all the other code it needs to run to figure out that's what you wanted.
Short answer, but: It really doesn't matter (unless you don't have a unique-constraint on your id column).
I'm writing a rails application, and I need to name one of my model Test, and inside that model I need a class attribute - when I tried the first one, I couldn't run any UT since Test ceased to be a module - so I ranamed to Tst. I haven't even tried naming a column class - I went with clss. What names would you use? Are there any conventions known amongs RoR developers for such situations?
I haven't seen anything for Test but class is typically changed to klass.
Ruby and Rails have several different objects part of a standard library. You cannot use an already-defined class name as name for your models.
For instance, you cannot call a model Thread or Object because Ruby already defines a Thread and Object class.
Likewise, Ruby has a library called Test::Unit so you can't use the Test namespace as model name.
There isn't a real full list of reserve objects because it really depends on your current environment. However, in order to successfully use Rails, you should at least have a basic Ruby knowledge so that you know the names of the most common standard library classes.
I've run up against this a few times (writing educational software--where you regularly want to model 'tests' :-). Depends exactly what you're modeling I suppose, but I usually opt for 'quiz' to avoid conflicts. I'd love to hear a better solution, since I find 'quizzes' an awkward plural.
Like dj2 said, class is usually done as 'klass'.
Please check the following page for Rails reserved words: http://reservedwords.herokuapp.com/ None of these words should be used as class or attribute name.
So we run a code quality tool called reek once in a while as part of our project. The tool basically looks for code smells and reports them. Here, we observed that we get "Duplication" smell every time we try to access a key in params more than once (As if we are making a method-call twice with same parameters or we are duplicating an if condition etc). However, params is just a Hash, right? Other hashes don't get duplication smell when their keys are accessed more than once.
Why is this so? What are params exactly? Does it make sense to cache params in a local variable then use them? Will it help or its the same? Or is there something wrong with the tool? Help!
With the current version it's best to run Reek only on your app/models folder, because it raises false positives against views and controllers.
params is a kind of DTO (data transfer object) close to the system boundary, and so its characteristics should be different than regular code. But Reek doesn't know that (yet). I plan to improve Reek in the near future so that it plays better with Rails. For now though, your best bet is to restrict it to looking at app/models (and maybe app/helpers and lib).
params is a method call that does a #params ||= #request.params
It might be that it thinks params is a complicated method, so it wants you to try and cache it in a variable, but, dont think that would be worth it especially since it is memoized (based on my rack_process.rb from Rails 2.2)
params[:foo] is a method-call to Hash#[], so reek is correct. I'm not familiar with reek, so I can't tell why other Hash accesses don't get counted the same. Hash#[] should be fast enough that you don't need to store it in a local variable unless you're in a very performance critical part of your code.
The only difference between the params Hash and a regular Hash is that it uses with_indifferent_access, meaning you can access any key with a String or a Symbol.
I believe every time you call params, there is an initialization step which generates method calls, i suppose you can try creating a params and checking number of calls.
this could be blind guess. :-)