Some helpful syntax/conventions in Rails to you
Hi guys, Tien
again, after I read some articles and my hands-on experience in some Rails projects. I write this post to summarize some helpful conventions that can improve your Rails knowledge.
Sip a cup of tea and enjoy it ❤️ Have fun guys!!
1. Use _
in the console to get the value of the previous command in your console
YOUR CONSOLE a = [1,2,3,4,5] User.where(id: _) => SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2, 3, 4, 5)
2. Existence Check Shorthand
Use &&=
 to set variables that may or may not exist. Using &&=
 will change the value only if it exists, removing the need to check its existence with if
. Use &&= to set variables that may or may not exist. Using &&= will change the value only if it exists, removing the need to check its existence with if.
# bad if something something = something.downcase end # bad something = something ? something.downcase : nil # ok something = something.downcase if something # good something = something && something.downcase # better something &&= something.downcase
3. map
/find
/select
/reduce
/include?
/size
Prefer map
 over collect
, find
 over detect
, select
 over find_all
, reduce
 over inject
, include?
 over member?
 and size
 over length
. This is not a hard requirement; if the use of the alias enhances readability, it’s ok to use it. The rhyming methods are inherited from Smalltalk and are not common in other programming languages. The reason the use of select
 is encouraged over find_all
 is that it goes together nicely with reject
 and its name is pretty self-explanatory.
3.1. count
 vs size
Don’t use count
 as a substitute for size
. For Enumerable
 objects other than Array
 it will iterate the entire collection in order to determine its size.
# bad some_hash.count # good some_hash.size
3.2. flat_map
Use flat_map
 instead of map
 + flatten
. This does not apply for arrays with a depth greater than 2, i.e. if users.first.songs == ['a', ['b','c']]
, then use map + flatten
 rather than flat_map
. flat_map
 flattens the array by 1, whereas flatten
 flattens it all the way.
# bad all_songs = users.map(&:songs).flatten.uniq # good all_songs = users.flat_map(&:songs).uniq
4. Conditional Variable Initialization Shorthand
Use ||=
 to initialize variables only if they’re not already initialized.
# bad name = name ? name : 'Bozhidar' # bad name = 'Bozhidar' unless name # good - set name to 'Bozhidar', only if it's nil or false name ||= 'Bozhidar'
**NOTE: Don’t use ||= to initialize boolean variables. Consider what would happen if the current value happened to be false.** # bad - would set enabled to true even if it was false enabled ||= true # good enabled = true if enabled.nil?
5. Underscores in Numerics
Add underscores to large numeric literals to improve their readability.
# bad - how many 0s are there? num = 1000000 # good - much easier to parse for the human brain num = 1_000_000
6. Convert a range to an array
I use some below syntax to convert a range to an array. I hope that you can apply it
(1..10).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
7. Get array characters from a string
# bad string.split(//) string.split('') # good string.chars
8. Prefer to use Time.current, Date.current or DateTime.current
rather than Time.now, Date.now, DateTime.now
.current
will use the Rails environment is set to, .now
will use server's timezone (Rails.application.config.time_zone
). If it's not set, then .current
 will be the same as .now
.Be careful when use them to avoid conflict and unmatched.
Time.current => Returns Time.zone.now when Time.zone or config.time_zone are set, otherwise just returns Time.now. DateTime.current => Returns Time.zone.now.to_datetime when Time.zone or config.time_zone are set, otherwise returns Time.now.to_datetime.
9. Predicate Methods
Prefer the use of predicate methods to explicit comparisons with ==
. Numeric comparisons are OK.
# bad if x % 2 == 0 end if x % 2 == 1 end if x == nil end # good if x.even? end if x.odd? end if x.nil? end if x.zero? end if x == 0 end
10. Hash#values_at
Use Hash#values_at
 when you need to retrieve several values consecutively from a hash.
# bad email = data['email'] username = data['nickname'] # good email, username = data.values_at('email', 'nickname')
11. Proc Application Shorthand
Use the Proc call shorthand when the called method is the only operation of a block.
# bad names.map { |name| name.upcase } # good names.map(&:upcase)
12. Single-line Blocks Delimiters
Prefer {…}
 over do…end
 for single-line blocks. Avoid using {…}
 for multi-line blocks (multi-line chaining is always ugly). Always use do…end
 for "control flow" and "method definitions" (e.g. in Rakefiles and certain DSLs). Avoid do…end
 when chaining.
names = %w[Bozhidar Filipp Sarah] # bad names.each do |name| puts name end # good names.each { |name| puts name } # bad names.select do |name| name.start_with?('S') end.map { |name| name.upcase } # good names.select { |name| name.start_with?('S') }.map(&:upcase)
Some will argue that multi-line chaining would look OK with the use of {…}, but they should ask themselves - is this code really readable and can the blocks' contents be extracted into nifty methods?
13. Defining Class Methods
Use def self.method
 to define class methods. This makes the code easier to refactor since the class name is not repeated.
class TestClass # bad def TestClass.some_method # body omitted end # good def self.some_other_method # body omitted end # Also possible and convenient when you # have to define many class methods. class << self def first_method # body omitted end def second_method_etc # body omitted end end end
14. Hash#each
Use Hash#each_key
instead of Hash#keys.each
 and Hash#each_value
 instead of Hash#values.each
# bad hash.keys.each { |k| p k } hash.values.each { |v| p v } hash.each { |k, _v| p k } hash.each { |_k, v| p v } # good hash.each_key { |k| p k } hash.each_value { |v| p v }
15. Hash#fetch
Use Hash#fetch
 when dealing with hash keys that should be present.
heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' } # bad - if we make a mistake we might not spot it right away heroes[:batman] # => 'Bruce Wayne' heroes[:supermann] # => nil # good - fetch raises a KeyError making the problem obvious heroes.fetch(:supermann)
16. Hash#fetch
 defaults
Introduce default values for hash keys via Hash#fetch
 as opposed to using custom logic.
batman = { name: 'Bruce Wayne', is_evil: false } # bad - if we just use || operator with falsy value we won't get the expected result batman[:is_evil] || true # => true # good - fetch works correctly with falsy values batman.fetch(:is_evil, true) # => false
17. Use Hash Blocks
Prefer the use of the block instead of the default value in Hash#fetch
 if the code that has to be evaluated may have side effects or be expensive.
batman = { name: 'Bruce Wayne' } # bad - if we use the default value, we eager evaluate it # so it can slow the program down if done multiple times batman.fetch(:powers, obtain_batman_powers) # obtain_batman_powers is an expensive call # good - blocks are lazy evaluated, so only triggered in case of KeyError exception batman.fetch(:powers) { obtain_batman_powers }
18. Hash#transform_keys
 and Hash#transform_values
Prefer transform_keys
 or transform_values
 over each_with_object
 or map
 when transforming just the keys or just the values of a hash.
# bad {a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[k] = v * v } {a: 1, b: 2}.map { |k, v| [k.to_s, v] }.to_h # good {a: 1, b: 2}.transform_values { |v| v * v } {a: 1, b: 2}.transform_keys { |k| k.to_s }
19. reverse_each
Prefer reverse_each
 to reverse.each
 because some classes that include Enumerable
 will provide an efficient implementation. Even in the worst case where a class does not provide a specialized implementation, the general implementation inherited from Enumerable
 will be at least as efficient as using reverse.each
.
# bad array.reverse.each { ... } # good array.reverse_each { ... }
20. Unused Variables Prefix
Prefix with _
 unused block parameters and local variables. It’s also acceptable to use just _
 (although it’s a bit less descriptive). This convention is recognized by the Ruby interpreter and tools like RuboCop will suppress their unused variable warnings.
# bad result = hash.map { |k, v| v + 1 } def something(x) unused_var, used_var = something_else(x) # some code end # good result = hash.map { |_k, v| v + 1 } def something(x) _unused_var, used_var = something_else(x) # some code end # good result = hash.map { |_, v| v + 1 } def something(x) _, used_var = something_else(x) # some code end
❤️ Thank you for reading and see you ❤️
Follow me: https://tienvm.com/
Donate me:Â tienvm.com/donate
Top comments (0)