I am working through a tutorial book and I came across something I had never seen before. In rails I am accustomed to getting the values of a relationship like this
<%= current_user.favorites.count %>
The author of the book used the & operator when doing this though, which appeared to do the same thing (I believe that I understand the & operator, I have just never seen it used like this)
<%= current_user&.favorites&.count %>
There was no explanation for this, so I took it as just another way to write it, but I have never seen this before in years of working with Rails and reading books/tutorials.
Is there a performance reason for doing it like this, or is it just personal preference?
It was inside a turbo_frame_tag if that makes any difference.
& is the safe navigation operator and prevents a NoMethodError if you call a method on Nil.
Its use here isn't really that strange - what you're calling an "association" is after really just a method generated what is presumably has_many :favorites. So here the author is calling the method no matter if the record exists or not and is then creating an extra db hit with a COUNT query. Not great.
Its all kind of silly too since you most like want to wrap it with some markup so you'll need an if anyways.
Using long chains of the safe navigation operator is regarded as an antipattern of sorts since it lets you violate the Law of Demeter with blatant disregard and masks bugs.
Related
Now that my controllers are expanding beyond the basic REST actions it can get somewhat confusing as to whether a given expression is either a built in method, a controller method, from the model, or a variable.
Would adding empty parentheses to my controller methods when I call them from other methods cause any problems down the road? Like so:
if customer.save?
subscription_checker()
end
I'm at least trying to always use an underscore in the names of the methods I create in order to make them look different from most of the built in methods.
Would adding empty parentheses to my controller methods when I call them from other methods cause any problems down the road?
This is a valid way to distinguish between variables vs methods in ruby, but "You're Doing It Wrong" ™
Part of the ruby paradigm is that you shouldn't typically care whether the thing you're referencing is a variable or a method. This makes the code easier to read and refactor; keeping the developer's attention focused on code's intent rather than its implementation.
This design pattern is often referred to as "bare words", and I highly recommend the following RubyTapas episode on the subject: http://www.virtuouscode.com/2012/10/01/barewords/
I would also recommend that you have a quick read through a ruby style guide, to see what common conventions are considered "good" or "bad" by the community. (Ruby code styles are extremely well conformed to by the community!) For example, from this guide:
Only omit parentheses for
Method calls with no arguments:
# bad
Kernel.exit!()
2.even?()
fork()
'test'.upcase()
# good
Kernel.exit!
2.even?
fork
'test'.upcase
In your particular code above, although it's hard to say for sure without knowing more context, I suspect that subscription_checker should actually be abstracted into a separate class rather than yet-another-method in the controller. But as I say, in order to give any concrete advice here I'd need to see more of the source file this is taken from.
I have a model and table that I believe is perfectly suited to STI. My table is called Finances and has two types: Income and Expenses. Besides type there are three other columns: description, amount, and date.
I'm getting very nervous using STI in Rails, since it requires some hacking. I'm too new to Rails to hack up the code. Even though it works, I don't understand it. That seems dangerous.
My question is, how do I set up my model, controller, and view if I do NOT use STI? Any best practices to group items in my model? Or do I just do Finances.where("type = 'Income'") before setting up a view?
Edit: I made a gist to show the code I'm working with. When I run it I get the error:
undefined method `incomes_path' for #<#<Class:0x007fbc95f60b40>:0x007fbc93883220>
First, using STI is standard for Rails, so there is no need to feel nervous. And no need for "hacking".
It has been used very successfully by many developers. And as you have seen, you can find tutorials and general information on the net.
If on the other hand, you decide NOT to use STI, you have the choice of using
(a) completely separate models with their own tables, which will result in a lot of duplicated code, or
(b) create you custom "STI-like" behaviour by hand.
The second option could at least be interesting to learn more about Rails.
For example, in your Finances model you would define a scope incomes, like
scope :incomes, where(:type => 'Income')
then you can do Finances.incomes.
Then, if you have methods that apply only to one of the types, you should check that all records effectively are of the needed type.
Personally, I would advice you to use STI. You get a lot of functionality for free and you are doing it the Rails way.
Imagine, for example, other developers reading your code, they will ask themselves, why you didn't use STI, blame it on ignorance and - if need be - refactor it using STI.
STI is best if you are using inheritance structure like this. You don't really need to use Finances.where("type = 'Income'"). You can simply use Income.all. see these posts if they help you.
http://www.therailworld.com/posts/18-Single-Table-Inheritance-with-Rails
http://juixe.com/techknow/index.php/2006/06/03/rails-single-table-inheritance/
Not sure what the difference between underscore (student_state) and tableize (student_states), other than tableize also pluralizes. However, not sure how they can be used
differently. Obviously, you can use tableize to reference table name in
database. But what different functionality does underscore provide, such as when you see :student_state compared to :student_states when used as symbols. Thanks for suggestions.
tableize will pluralize your string whether the original was singular or plural, while underscore will only add underlines.
While this may seem trivial, it's all about abstracting the details of database implementation away from the developer. If, down the road, Rails began formatting table names differently, the only method that would need to change would be tableize. All other places in the Rails code that refer to table names can stay the same, because they're still calling the tableize method. A change to the underlying structure of rails is therefore limited and much less damaging.
This is referred to as "orthoganality" in computer science. Now that you know what it means, try to throw it around in conversation to make yourself look smarter. Did it work for me? :)
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.
I'm still new to ROR, so pardon the simplicity of the question...
So http://www.example.com/controller/:id displays a record in my table, with :id being a number (1,2,3 etc.).
Is there a way I can have :id in the URL be the value of a field in the displayed record? Such that I can have http://www.example.com/controller/record_field? I want to have a human-friendly reference to specific records in my table. I'm sure this must be possible. Do I change something in routes.rb?
Thanks for the help!
The cleanest way is to add a new find method in your model (or simply use the find_by_fieldname Rails gives you in your control). Then you'll have your controller use that method instead of the regular find(params[:id]) to pull your model record.
Check out Ryan B's screencast on this here. It's pretty easy, and he's a good teacher, so you shouldn't have any problems.
I use the excellent rails plugin named friendly_id.
http://github.com/norman/friendly_id/tree/master
That should sort you out nicely. It is well documented too.
Take care around fields that might have modern Greek characters—might need to figure a work around for those.
Jon Smock's solution will work, too. I tend to prefer the following.
class Hamburger << ActiveRecord::Base
#this normally defaults to id
def to_param
name
end
end
class SomeModelController << ApplicationController
def show
#hamburger = Hamburger.find(params[:id]) #still default code
end
end
#goes in some view
This is the <%= link_to "tastiest hamburger ever", url_for(#hamburger) %>.
This is, loosely speaking, an SEO technique (beautiful URLs are also user-friendly and I suggest them to absolutely everyone even if you don't care about SEO, for example on pages behind a login). I have a more extended discussion of Rails SEO, which includes other tips like this, here.
Important tip: You should consider, at design-time, what you are going to do if the param should change. For example, in my hamburger scenario, it is entirely possible that I might rename "Sinfully Delicious Cheeseburger" to "Triple Bypass". If that changes URLs, there are some possible implications, such as breakage of customer links to my website. Accordingly, for production use I usually give these models an immutable permalink attribute which I initialize to be human-meaningful exactly once. If the object later changes, oh well, the URL stays the same. (There are other solutions -- that is just the easiest one.)