4

I assume alot of these are built in or convetions, but methods like belongs_to or require uses a symbol for the model name it takes as an argument.

And when it comes to methods like before_action, I'm not sure why there is a symbol in front of the controller actions as in the brackets below.

before_action :find_course, only: [:show, :edit, :update, :destroy]

Are all of these symbols used as a key of a hash or do most methods take symbols as its arguments?

Robert
  • 301
  • 5
  • 12
  • "there is a symbol in front of the controller actions" - what symbol? what actions? – Sergio Tulentsev Jul 25 '17 at 06:40
  • 1
    `before_action`, in this case, is a method that takes two arguments. `find_course` and `{ only: [:show, :edit, :update, :destroy] }`. How it interprets these is totally up to the implementation. `:show`, `:edit` and others here are not "controller actions". They're just symbols. Which happen, intentionally, to match names of existing action methods, yes. – Sergio Tulentsev Jul 25 '17 at 06:42
  • 1
    Read this, it might help: https://stackoverflow.com/questions/26786542/why-do-callbacks-use-symbols-in-ruby-on-rails – Deepesh Jul 25 '17 at 06:49
  • 1
    @Deep So using a symbol is the cheapest way to refer to something and these methods are all referring to something like as it is referring to the :find_course method and :show controller action. Thanks! I think I understand it better!! – Robert Jul 25 '17 at 07:08

2 Answers2

6

Second one. Most methods take symbols as their arguments. Here is why: When to use symbols instead of strings in Ruby?

This is the method signature of before_action:

before_action(names, options)

As you can see, it takes first a name and then some options as its argument. By convention, options is a hash. Because Ruby allows you to drop a lot of "line noise", the brackets around the hash are implicit. You could write the same line as:

before_action(:find_course, { only: [:show, :edit, :update, :destroy] })

So :find_course is not the key for the hash, but only is.

Furthermore, :find_course is not the name of a model but the name of a method. By passing the method name (as a symbol) to before_action, the method will be executed before each request is processed (i.e. before #show for example). Through the options, it is possible to limit the action to certain operations. These are again provided as symbols, since they are internal identifiers. Technically, they all reference methods on the controller again.

Passing symbols that reference methods or classes is a very common practice in Rails. belongs_to uses the same convention to add association methods to your models (belongs_to :user). Rails will attempt to connect this method name to a model called User unless you specify otherwise. This is part of the magic of Rails that makes it very easy to use, but a bit hard to understand in the beginning.

Having a good understanding of Ruby and symbols vs. strings helps you make more sense of this.

Edit:

To understand what "internal identifier" means, check out the question linked to by Deep in a comment to your question: Why do callbacks use symbols in Ruby on Rails It explains why you need to reference a method, instead of doing something like this:

before_action(find_course)

In summary, this would execute find_course and pass its result to before_action, which is not what you want. So you need to reference the method somehow so that it can be called later.

In other languages, this could be done with strings or by passing in a function object. For example, in Python you could do something before_action(print). This would pass a reference to the function without calling it. Sadly, this is not possible in Ruby, so we need to pass in a string or symbol with the name of the method, which brings us back to the first linked question about the benefits of symbols over strings as references.

m. simon borg
  • 2,515
  • 12
  • 20
jdno
  • 4,104
  • 1
  • 22
  • 27
  • I looked at your link and the answer mentions internal identifiers as you do too in your answer. Can you elaborate on what you mean when you say internal identifier? – Robert Jul 25 '17 at 07:00
  • Edited the answer, but also check out the question linked by Deep. People have answered this better than I could. – jdno Jul 25 '17 at 07:15
  • "Sadly, this is not possible in Ruby" - possible. Just not used by rails. :) – Sergio Tulentsev Jul 25 '17 at 07:20
  • 1
    @SergioTulentsev The only way I know how to do this is by passing the method as a block. But this is not the same as what you do in Python. Passing a function as an object is imho not possible in Ruby. Can you point me to an explanation or example how this would look like? – jdno Jul 25 '17 at 07:46
  • @jdno: I meant something like `before_action method(:find_course)`. But in this exact scenario it, of course, wouldn't work, because at class level there's no method `find_course` and it is therefore impossible to obtain a reference to it. So one must use symbols (or some other way of indirection) here. – Sergio Tulentsev Jul 25 '17 at 07:48
-3

Symbols can be a lot of things: variable, action, entity, object, column, so it's nearly impossible to "It's the equivalant of..." Since it can be the equuvalant of a lot of things in a lot of languages.

This link here will tell you that symbols are both string and integer representation, that's why you can do :symbol.to_s to get the string value or :symbol.to_i to have its integer value.

I hope this helps, I'm also learning the ruby fundamentals, so I'm talking with both the link I shared and the experience I have

Jaeger
  • 1,686
  • 1
  • 30
  • 50
  • This is a complete nonsense. `Symbol#to_i` is not implemented, symbols can by no means “be an action,” neither “column” etc. – Aleksei Matiushkin Jul 25 '17 at 06:51
  • If you use CarrierWave for example, you have to set it up as the following: 'mount_uploader :column, YouUploader', so yes it can be a column. For the action, just check OP's question, it contains actions in his example – Jaeger Jul 25 '17 at 06:53
  • @Jaeger: a symbol is a symbol, never a column or anything other than a symbol. It is _used_ to refer to the column indirectly, but it is not the column. – Sergio Tulentsev Jul 25 '17 at 06:55
  • @mudasobwa: to be fair to the guy, the article is from 2005! Maybe at that time `Symbol#to_i` was returning its object_id or something. But one certainly must not read 12-year old blog posts for learning. No excuse here. – Sergio Tulentsev Jul 25 '17 at 07:00
  • I love being downvoted as hell because the fact that's symbols are references is more than obvious to me. Well, lesson learned, my bad :( – Jaeger Jul 25 '17 at 07:03
  • @SergioTulentsev It had a weird behaviour in [`1.8`](https://ruby-doc.org/core-1.8.7/Symbol.html#method-i-to_i) and was removed in `1.9`. – Aleksei Matiushkin Jul 25 '17 at 07:04
  • Symbols are **by no means references**. – Aleksei Matiushkin Jul 25 '17 at 07:04
  • @Jaeger: except the liberal wording ("symbol can be a column"), your answer is also factually incorrect. Symbols in modern ruby don't have an integer representation. – Sergio Tulentsev Jul 25 '17 at 07:04
  • @mudasobwa: "Symbols are by no means references" - now we're entering terminology war area :) Of course, they're not references of the pointer-kind. But very often, like that before_action case, they kinda _do_ refer to something. How do you call that? – Sergio Tulentsev Jul 25 '17 at 07:07
  • @SergioTulentsev ok I get it now, I used to do :symbol.to_s with ruby 1.7, when I started to learn it, that's why I thought it still worked even though I never used it after my small tests – Jaeger Jul 25 '17 at 07:09
  • @SergioTulentsev in the aforementioned `before_action` case, symbol `:find_course` is _a first parameter in call to DSL function_, nothing else. At this point it does not refer anything and I can in 5 seconds supply a monkeypatch that will treat is an exception and `raise :find_course`. It does not refer anything in this particular code. – Aleksei Matiushkin Jul 25 '17 at 07:10
  • @mudasobwa: as I said, of course, there's no hard link. But there is a logical link. Meta-link, if you will. There better be the method `find_course` there, or you get a runtime error. – Sergio Tulentsev Jul 25 '17 at 07:14