Difference between "Class#message" and "Class.message" notation - ruby-on-rails

This is a very basic ruby question. What is the difference between ClassName#message and ClassName.message?
I am reading a basic Ruby guide and I see both references used quite a lot. It seems that mainly in the code ClassName.message is used but in the documentation ClassName#message is used.
Is the # simply documentation convention? Will only the . work for message passing in actual code? Or is there something that I am just missing?
Does the meaning differ in Rails at all?

In code you use object.method. In documentation however, Class#method denotes an instance method (e.g. String#upcase), whereas Class.method or Class::method denotes a class/module method (e.g. Math.log10).

The # is used in the documentations to point out the difference between class methods and instance methods.
In the code, you'll be using . in all the cases.

'#' is rails convention. In rails className#Message will map to Message action of your className controller.
Ex:
match "profile" => "users#show"
This will map root_path/profile => Show method(or action) of UserController.

Related

Ruby symbol naming

I am currently reviewing a clients code base for the company I am interning for. The API is built with Ruby on Rails. I am new to Ruby, but have programmed in other languages, so looking through the code (and some tutorials), I have been able to understand most of what is going on, but there is a line that looks like the code below that is throwing me off. Why do the names of the symbols have equals in front? This feels illegal, but ruby is kinda cool. Thank you for your help.
delegate :name=, :description=, :tags=, to: :user
Another point: In Ruby, as a pattern you don't use the prefixes set or get, instead you use just the attribute name for the get and suffix = for the set. Example: setName and getName methods would be name= and name respectively.
Ruby allows you to use the setter method in these sintaxes: obj_instance.name = 'Name' (You can omit the () and use space before caracteres like =) or obj_instance.name=('Name').
A ruby symbol has very few restrictions concerning the characters it can have, and it's mainly linked to the "easy" representation we usually choose.
It's totally possible to have the following symbols:
:"hello/world"
:€
:"a+b"
It becomes a bit trickier when the symbol is used to represent a method, because we like the easy syntax that comes with it, but it's actually the same as sending the symbol using e.g. public_send:
foo.public_send(:"a+b")
This code will work if you define a method named :"a+b". Of course, you can't define it with the usual def, but it's still possible.
Now, some methods such as name= offer an additional semantic, so that the following are equivalent:
object.name = "Fubar"
object.send(:name=, "Fubar")

Rails - Call a method form a model or helper with an alias

I have a helper called GlobalHelper.
There are a couple of constants (e.g. GLOBAL_URL) and methods (e.g. self.get_url) in it.
I'm trying to make an alias or an equivalent of the macros in C (#define URL) to access the constant and methods from any of my views and controllers easily.
For now I have to do it like this:
GlobalHelper.get_url(GlobalHelper::URL_TYPE_PAGE, ["page1"])
And I want to get rid of the GlobalHelper everywhere with alias/macro to get a code like this instead:
aliasmethod(aliasconstant, ["page1"])
How can I do that?
ruby is not c, so you should take a look how to write ideomatic ruby code before trying to bring such concepts into your project.
since i don't know what exactly your get_url method does, i can only give limited recommendations.
one thing that would probably result in much nicer code is using symbols instead of constants:
GlobalHelper.get_url(:page, ["page1"])
when using a Module instead of Class you can include it and call the method directly:
include GlobalHelper
get_url(...)
these are just examples of what could be done. not saying that this is better than explicitly calling GlobalHelper directly. nothing wrong with that at all.

If ActiveRecord::Base#create is deprecated in 3.2.13, how am I using it still?

I'm running 3.2.13 and following the standard "railstutorial.org" I've run into a question. I'm still getting the hang of switching from a C++/Java programming mindset, and trying to understand normal calling conventions.
I can use my class (User < ActiveRecord::Base) like:
User.create(email: "email", password: "password", password_confirmation: "password")
The doc for the method indicates that it is deprecated. I also see no reference to a def create in my ActiveRecord gem source.
Since the call is not using a Hash, what is the name of that kind of invocation? Is it the same if the arguments were wrapped in curly brackets?
Two questions are being asked here.
First question: method deprecation
Changes were made in this commit.
The create method was removed from ActiveRecord::Base and inserted into a separate module called ActiveRecord::Persistence.
Regarding what APIDock told you... the method was "deprecated or moved." If you look halfway down the list of suggestions, you will see ActiveRecord::Persistence#create. This is where the method moved to.
Note that ActiveRecord::Persistence#create is used internally. When calling create on an ActiveRecord model (not object) in your application code, you are invoking ActiveRecord::Relation#create.
ActiveResource::Base#create was introduced in Rails 2.0 and is unrelated to ActiveRecord.
Second question: hash as arguments
Examining the source for ActiveRecord::Relation#create shows the following:
# File activerecord/lib/active_record/relation.rb, line 85
def create(*args, &block)
scoping { #klass.create(*args, &block) }
end
See the splat argument *args? This tells Ruby to pass all remaining arguments into args, no matter how many there are. Ruby/Rails' ducktyping magic sees a bunch of key-value pairs and assumes it to be a hash.
Rails is a bit loose with requiring curly brackets for hashes in arguments, just as it is loose about wrapping all arguments in parentheses. Generally, Rails will infer a hash when you pass in a series of key-value pairs. Sometimes this causes trouble when passing in multiple hashes, like in a complex form_for method.
If you have erratic behavior with curly brackets absent, insert them. Clearly defining hashes will allow you to ensure proper behavior.
Read more about Ruby splats here.
"Deprecated" doesn't mean "no longer available". It means it will be no longer available soon.

Finding options to pass to methods in Rails

How are you supposed to find the different options you can pass to methods in Rails? For instance I want to know the options I can pass to validates. I can't find them nowhere in the documentation.
api dock is useful and it also shows the source code http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates
As you know it's not possible to document hash options in the signature so you must either rely on the quality of the documentation or read the source code.
In this case the docs show some examples that cover pretty much all the default validators. Note that it cannot document all the available since they can be expanded dinamically.
>> ActiveModel::EachValidator.descendants
=> [Paperclip::Validators::AttachmentSizeValidator, ActiveModel::Validations::WithValidator, ActiveModel::Validations::ExclusionValidator, ActiveRecord::Validations::AssociatedValidator, ActiveModel::Validations::ConfirmationValidator, ActiveModel::Validations::PresenceValidator, ActiveModel::Validations::FormatValidator, Paperclip::Validators::AttachmentContentTypeValidator, Paperclip::Validators::AttachmentPresenceValidator, ActiveRecord::Validations::UniquenessValidator, ActiveModel::BlockValidator, ActiveModel::Validations::NumericalityValidator, ActiveModel::Validations::AcceptanceValidator, ActiveModel::Validations::InclusionValidator, ActiveModel::Validations::LengthValidator]
Or:
ActiveModel::EachValidator.descendants.map { |klass| klass.name.split("::").last.sub(/Validator$/, '').underscore }
=> ["attachment_size", "with", "exclusion", "associated", "confirmation", "presence", "format", "attachment_content_type", "attachment_presence", "uniqueness", "block", "numericality", "acceptance", "inclusion", "length"]
The starting point is always the official Rails documentation. For instance, here's the documentation of the validates method.
However, keep in mind that Rails is a constantly evolving framework. Unfortunately, this means that not all methods are fully documented and sometimes you need to dig into the source code directly to understand how a method works.

See where a symbol is defined in irb

I work on a pretty large rails project at work. Sometimes I need to hunt down class / constant definitions. Is there some built-in method in Ruby to do this for me? Example:
irb> SOME_CONSTANT.__file__
=> /some/path/to/a/file
This isn't exactly what you're looking for, but methods do have a .source_location method on them. You can use this to find out where a class is actually implemented. (Since ruby lets you reopen classes, this could be in multiple places)
for example, given an instance of an object, i:
i.methods.map do |method_name|
method_obj = i.method(method_name)
file, line = method_obj.source_location
file #map down to the file name
end.uniq
will give you a list of all the files where i's methods are implemented.
This will work for classes that have at least 1 method implemented in ruby. It won't work for constants, though.
At the very beginning before any file is loaded, insert a line that defines the class/constant that you want to check as something other than a module. For example, suppose you have class or other kind of constant A within your code, and want to know where it is defined. Then, at the very beginning of the main file, write
A = nil
Then, when the program is run, whenever it first meets the definition of class/constant A, it will show something like
some_path_to_a_file:line_number in `some_method': A is not a class (TypeError)
or
some_path_to_a_file:line_number: warning: already initialized constant A
Then, some_path_to_a_file:line_number will be the location where A is defined.
If you're using Ruby 1.9.2, #YenTheFirst's answer is correct: call #source_location on a Method object.
If you're using Ruby 1.8.7, then #source_location doesn't exist (yet). You'll need something like this implementation of a method. (There's another one or two floating around, but I can't find the other one real quick).

Resources