I learned from an elite engineer in the workplace that reading a good code will be a catalyst for growth as an engineer, so I put it into practice immediately! I will share it by the way.
By learning good code, you will be able to write code that is highly readable and has few bugs, so please refer to it as well.
Start with link_to.
def link_to(name = nil, options = nil, html_options = nil, &block)
html_options, options, name = options, name, block if block_given?
options ||= {}
html_options = convert_options_to_data_attributes(options, html_options)
url = url_for(options)
html_options["href"] ||= url
content_tag("a", name || url, html_options, &block)
end
From Ruby on Rails Official API, to name (when block = do ~ end is not used) The character string to be displayed, url information in options, and the value you want to set in the HTML a tag such as class and rel are passed in html_options.
It is assumed that options and html_options are passed in hash format.
def link_to(name = nil, options = nil, html_options = nil, &block)
The description of = nil in the argument definition means that when no value is assigned, nil is assigned to the argument. & Block in the 4th argument is a description to receive "block". If you read this article, a block is used when passing a chunk of code, not a value as an argument ***. *** It seems that the chunk of code passed is called a block ***.
When writing link_to do ~ end, ~ is substituted here.
html_options, options, name = options, name, block if block_given?
block_given? (Ruby Reference Manual) From the reference manual, block_given? becomes true when the block is passed to the link_to method, and the contents of the if statement are executed. In other words, Multiple assignment (Ruby reference).
For example, when using block, from Ruby on Rails Official API
link_to(options = {}, html_options = {}) do
# name
end
Will be described as In this case, options (url information) will be passed to name, which is originally the display name, and html_options, which defines class and id, will be passed to options, which is url information, from the first line of the link_to definition.
Therefore, the role of this line is to reassign as defined by the method so that it works as the method user intended. (For example, the value of name to which url information has been assigned is reassigned to options)
options ||= {}
||=Is a description that the value of the right side is assigned when the left side is false or is not defined. In the first line, when no value is passed to the argument, nil is assigned to options, so the content of options is nil, that is, false. At this time, {} (empty hash) is assigned to optins.
html_options = convert_options_to_data_attributes(options, html_options)
A method called convert_options_to_data_attributes is called.
The definition of this method is link here
def convert_options_to_data_attributes(options, html_options)
if html_options
html_options = html_options.stringify_keys
html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
method = html_options.delete("method".freeze)
add_method_to_attributes!(html_options, method) if method
html_options
else
link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {}
end
end
Let's read convert_options_to_data_attributes.
If html_options exists, the third line will be executed.
html_options = html_options.stringify_keys
stringfy_keys is a rails method that converts a hash from symbol format to string format.
html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
In short, if options or html_options has a setting of remote: true, true will be assigned to the key data-remote in string format.
You'll understand why this happens if you understand the contents of the rails method link_to_remote_options ?. I will explain in detail in the interpretation of the else statement, so please refer to that first.
method = html_options.delete("method".freeze)
Delete for hash deletes the key that matches the argument value → returns the deleted key value Masu The argument is method ".freeze. freeze does not delete the first function of delete, the second function. , That is, returns only the value of method.
Therefore, the value of the key method of html_options is assigned to the variable method. (HTML method setting value) This way of writing is interesting.
add_method_to_attributes!(html_options, method) if method
In addition, if the method value is set, call the add_method_to_attributes! Method. Since it has a! Mark, it is a destructive method.
The add_method_to_attributes! method is defined as follows.
def add_method_to_attributes!(html_options, method)
if method_not_get_method?(method) && html_options["rel"] !~ /nofollow/
if html_options["rel"].blank?
html_options["rel"] = "nofollow"
else
html_options["rel"] = "#{html_options["rel"]} nofollow"
end
end
html_options["data-method"] = method
end
The conditional expression of if is an AND condition. One item of AND condition is the return of method_not_get_method? Method value.
The definition expression of this method is omitted, but as the name suggests, true is returned for methods other than get (such as delete). (It's the naming method that is also listed in the readable code!)
The second item of the AND condition is the third item in the! Section of the Ruby reference. True if the html_options key rel value is not nofollow.
Executed when the above-mentioned AND condition is satisfied.
if html_options["rel"].blank?
html_options["rel"] = "nofollow"
else
html_options["rel"] = "#{html_options["rel"]} nofollow"
end
Let's go at once. When the value of the key rel of html_options is empty, the character string nofollow is assigned. If the value of the key rel of html_options contains some value, add the string nofollow in addition to the set value.
When interpreted in combination with the if statement on the second line, rel = "nofollow" will be displayed regardless of whether the value is set in rel for methods other than get.
By the way, the meaning of nofollow is ["Exclude links from crawl"](https://www.seohacks.net/blog/column/1140/#:~:text=rel%3D%E2%80%9Dnofollow%E2 % 80% 9D% E3% 81% AE% E6% 84% 8F% E5% 91% B3,% E3% 81% AA% E3% 81% 8F% E3% 81% AA% E3% 82% 8B% E3% 81% A8% E3% 81% 84% E3% 81% 86% E3% 81% 93% E3% 81% A8% E3% 81% A7% E3% 81% 99% E3% 81% AD% E3% 80% 82) That's right.
I'm not sure why it's better to add nofollow to methods other than get, and I can only guess, so I'll omit it. For more information on how to use rel itself, see [here](https://saruwakakun.com/html-css/basic/link-rel#:~:text=%E2%86%91%20rel%E3%81%AF%E3 % 80% 8Crelation% EF% BC% 88% E9% 96% A2% E4% BF% 82,% E3% 81% A7% E7% A4% BA% E3% 81% 99% E3% 82% 8F% E3% 81% 91% E3% 81% A7% E3% 81% 99% E3% 81% AD% E3% 80% 82)
html_options["data-method"] = method
On the contrary, if it is specified as get method, it branches to else statement by the if statement on the second line. The above code will be executed.
The HTTP method type is assigned to the key "data-method" of html_options. Since it is "data-", it is defined as a custom attribute.
Finally, the interpretation of the add_method_to_attributes! method is complete.
(Repost)
def convert_options_to_data_attributes(options, html_options)
if html_options
html_options = html_options.stringify_keys
html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
method = html_options.delete("method".freeze)
add_method_to_attributes!(html_options, method) if method
html_options
else
link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {}
end
end
Returns the hash html_options with the two values assigned on lines 4 and 6.
If no value is passed to html_options
link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {}
Is executed.
It's a ternary operator. First, link_to_remote_options? is called.
def link_to_remote_options?(options)
if options.is_a?(Hash)
options.delete("remote".freeze) || options.delete(:remote)
end
end
The contents of the if statement are executed when the value of options is a hash
However, even if remote is set, if remote: false is defined, the value of one item will be false. Two items are called there, and this time the remote setting is deleted because there is no description of freeze.
In short, link_to_remote_options? Returns false if OR false is not specified, and true if the value of remote is true.
If the ternary operator returns true for one item, that is, remote: true is set, the symbol "data-remote" => true is the return value of convert_options_to_data_attributes.
The reason why the value of the key data-remote of html_options is set in any of the if statements in convert_options_to_data_attributes is that the custom attribute is set regardless of whether the remote setting value is passed to the argument of the link_to method, options or html_options. It seems that the value of remote is displayed in html.
The pattern of how to write the passing of the value to link_to is omitted here.
(Repost)
def link_to(name = nil, options = nil, html_options = nil, &block)
html_options, options, name = options, name, block if block_given?
options ||= {}
html_options = convert_options_to_data_attributes(options, html_options)
url = url_for(options)
html_options["href"] ||= url
content_tag("a", name || url, html_options, &block)
end
Up to the 4th line, the value of html_options has been formatted.
url = url_for(options)
The url_for method is called.
def url_for(options)
if options[:only_path]
path_for options
else
full_url_for options
end
end
path_for is a method that outputs a relative path, and full_url_for is a method that outputs an absolute path. Outputs the relative path when the value of the option key only_path is true.
html_options["href"] ||= url
Assign the generated path to the key href of html_options. What you can see from this is that you can forcibly specify the URL by using href as the key for the third factor of link_to.
Whether it's used or not ...
content_tag("a", name || url, html_options, &block)
[content_tag is a view helper]. (https://apidock.com/rails/ActionView/Helpers/TagHelper/content_tag) Output html tag.
The first argument is the type of html tag, in this case .
The second argument is the character string to display. In this case, if name does not exist, the URL will be automatically displayed as a character string.
If you pass class: "XXX" etc. in hash format to html_options, it will be displayed as text .
Also, as you can see from the description & block, if a block is passed to link_to (if it is written in the format link_to ~ do ~ end), the block is passed to content_tag as it is.
This is the end of reading comprehension of link_to.
① Arrange the order of the assigned arguments ② Format values such as url and method ③ Display with content_tag
that's all.
** First point ** By knowing the method definition in the first place, it seems that you will be able to output as you expected. For example, if you use a view helper, you can reduce the effort of writing code by trial and error ⇔ building and outputting the desired display.
** Second point ** ||=Or&I had seen how to write a block, but I managed to write the code without it, so I didn't understand the meaning and it was a good opportunity.
For example||=In that case, it means that if the variable is undefined or nil, it is assigned, but if you write it without knowing it, you can simply express in one line where you would write complicatedly using an if statement.
As I mentioned at the beginning, by learning how to write good and smart code, you will be able to write code that is easy to maintain and error-free.
I will continue to learn in the future!