Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the use of ! in rails

What is the use of ! in rails?

Especially in this line: From HArtl tutorial

users = User.order(:created_at).take(6)
50.times do 
    content = Faker::Lorem.sentence(5)
    user.each { |user| user.microposts.create!( content: content )}
end

Basically this is creating tweets/microposts for 6 users.

I am really wondering why need to use !

like image 630
eric Avatar asked Oct 17 '25 15:10

eric


1 Answers

The important thing to remember is that in Ruby a trailing ! or ? are allowed on method names and become part of the method name, not a modifier added on. x and x! and x? are three completely different methods.

In Ruby the convention is to add ! to methods that make in-place modifications, that is they modify the object in fundamental ways. An example of this is String#gsub which returns a copy, and String#gsub! which modifies the string in-place.

In Rails this has been ported over to mean that as well as situations where the method will raise an exception on failure instead of returning nil. This is best illustrated here:

Record.find_by(id: 10) # => Can return nil if not found
Record.find_by!(id: 10) # => Can raise ActiveRecord::RecordNotFound

Note that this is not always the case, as methods like find will raise exceptions even without the !. It's purely an informational component built into the method name and does not guarantee that it will or won't raise exceptions.

Update:

The reason for using exceptions is to make flow-control easier. If you're constantly testing for nil, you end up with highly paranoid code that looks like this:

def update
  if (user.save)
    if (purchase.save)
      if (email.sent?)
        redirect_to(success_path)
      else
        render(template: 'invalid_email')
      end
    else
      render(template: 'edit')
    end
  else
    render(template: 'edit')
  end
end

In other words, you always need to be looking over your shoulder to be sure nothing bad is happening. With exceptions it looks like this:

def update
  user.save!
  purchase.save!
  email.send!

  redirect_to(success_path)

rescue ActiveRecord::RecordNotFound
  render(template: 'edit')
rescue SomeMailer::EmailNotSent
  render(template: 'invalid_email')
end

Where you can see the flow is a lot easier to understand. It describes "exceptional situations" as being less likely to occur so they don't clutter up the main code.

like image 137
tadman Avatar answered Oct 20 '25 04:10

tadman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!