简体   繁体   中英

Rails: how can I optimize this action

The action bellow creates a new comment.

  • A user has many statuses
  • A status has many comments

How can optimize this action so that head 401 and return is not repeated many times.

def create
  @user = User.where(id: params[:user_id]).first
  if @user
    if current_user.friend_with?(@user) or current_user == @user
      @status = @user.statuses.where(id: params[:status_id]).first
      if @status
        @comment = @status.comments.build(params[:comment])
        @comment.owner = current_user
        if @comment.valid?
          @comment.save
          current_user.create_activity(:comment_status, @comment, @user)
        else
          head 401 and return
        end
      else
        head 401 and return
      end
    else
      head 401 and return
    end
  else
    head 401 and return
  end
end

Thank you.

You have a lot of excessive checking and branching in your code, so it can be simplified to this:

def create
  success = false

  @user = User.find(params[:user_id])
  current_user_is_friend = current_user.friend_with?(@user) || current_user == @user

  if @user && current_user_is_friend && @status = @user.statuses.find(params[:status_id])
    @comment = @status.comments.build(params[:comment])
    @comment.owner = current_user
    if @comment.save
      current_user.create_activity(:comment_status, @comment, @user)
      success = true
    end
  end

  render(status: 401, content: '') unless success
end

A few things I did:

  • Combine a lot of the if conditions, since there was no need for them to be separate.
  • Change where(id: ...).first to find(...) since they're the same. Note that, if the find fails, it will give a 404. This may make more sense, though (I think it does)
  • Don't call @comment.valid? right before @comment.save , since save returns false if the object wasn't valid.
  • Use || instead of or for boolean logic ( they're not the same ).
  • Use render(status: ..., content: '') instead of head ... and return .
  • Use a boolean variable to track the success of the method.

I would advise that you try and pull some of this logic out into models. For example, User#friend_with should probably just return true if it's passed the same User.

When do you want to return 401 ?

  1. when a user has not been found
  2. when a user is not a current user or is not a friend of that user
  3. when a status has not been found
  4. when new comment has not been successfully created

Instead of using so many conditionals, you can use methods that raise exceptions. When you do so, you can rescue from that exceptions with the desired behavior (rendering 401 ).

So my suggestions for listed conditions are:

  1. use find! instead of where and then first .
  2. raise something, preferably custom exception ( NotAFriendError )
  3. same as 1., use find!
  4. use create! , it's an equivalent to new and then save! which will raise ActiveRecord::RecordInvalid exception if it fails on validation.

Here's the result:

def create
  begin
    @user = User.find!(params[:user_id])
    raise unless current_user.friend_with?(@user) || current_user == @user
    @status = @user.statuses.find!(params[:status_id])
    @comment = @status.comments.
      create!(params[:comment].merge(:owner => current_user))
  rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid
    head 401
  end
  # everything went well, no exceptions were raised
  current_user.create_activity(:comment_status, @comment, @user)
end
def create
  @user = User.where(id: params[:user_id]).first
  if @user
    if current_user.friend_with?(@user) or current_user == @user
      @status = @user.statuses.where(id: params[:status_id]).first
      if @status
        @comment = @status.comments.build(params[:comment])
        @comment.owner = current_user
        if @comment.valid?
          @comment.save
          current_user.create_activity(:comment_status, @comment, @user)
          everythingOK = true
        end
      end
    end
  end
  head 401 and return unless everythingOK
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM