The Art Of Self-Defense - How To Protect Yourself From Nils

The Art Of Self-Defense - How To Protect Yourself From Nils

Presentation given on Łódź Ruby User Group.

347a1b64f3a6e38981bc99b53919e2b1?s=128

karol.galanciak

January 13, 2016
Tweet

Transcript

  1. The art of self-defense - how to protect yourself from

    nils Karol Galanciak - full-stack developer at Twitter: @Azdaroth
  2. NoMethodError: undefined method 'name' for nil:NilClass

  3. 1. Use right set of methods

  4. 1. Use right set of methods 1. Prefer Hash#fetch over

    Hash#[] name = params[:name] name = params.fetch(:name)
  5. 1. Use right set of methods 2. Use bang finder

    methods for required objects user = User.find_by(name: name) user = User.find_by!(name: name)
  6. 1. Use right set of methods 3. Use Hash#dig for

    hashes from input you don’t own payload = { data: { type: "users", attributes: { email: "email@example.com" }, relationships: { source: { data: { type: "sources", id: 20 } } } } } source_id = payload[:data][:relationships][:source][:data][:id] source_id = payload.dig(:data, :relationships, :source, :data, :id)
  7. 2. Null Object Pattern

  8. 2. Null Object Pattern # controller def current_user @current_user ||=

    User.find_by(id: user_id) || GuestUser.new end # model class GuestUser def name "Anonymous user" end end # view <%= current_user.name %>
  9. 2. Null Object Pattern class GuestUser def name "Anonymous user"

    end def comments Comment.none end end
  10. 2. Null Object Pattern class Comment::Persistence attr_reader :logger private :logger

    def initialize(logger: nil) @logger = logger end def save!(comment) comment.save! logger.log("comment: #{comment.attributes} created!") if logger end end
  11. 2. Null Object Pattern class Comment::Persistence attr_reader :logger private :logger

    def initialize(logger: NullLoger) @logger = logger end def save!(comment) comment.save! logger.log("comment: #{comment.attributes} created!") end module NullLogger def self.log(*) end end end
  12. 3. Do Not Make Demeter Sad

  13. 3. Do Not Make Demeter Sad comment.author.name

  14. 3. Do Not Make Demeter Sad class Comment < ActiveRecord::Base

    belongs_to :author delegate :name, to: :author, prefix: true, allow_nil: true end class Comment < ActiveRecord::Base belongs_to :author def author_name author && author.name || "Anonymous" end end comment.author_name
  15. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value * percentage end end
  16. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value.to_d * percentage end end
  17. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value.to_s.to_d * percentage end end
  18. 5. Use proper database constraints class CreateComments < ActiveRecord::Migration def

    change create_table :comments do |t| t.integer :author_id, null: false t.text :content, null: false t.timestamps end add_foreign_key :comments, :authors end end
  19. Bonus: Never, ever, use Object#try and safe navigation operator &.

  20. Bonus: Never, ever, use Object#try and safe navigation operator &.

    comment.try(:author).try(:address).try(:primary) .try(:city).try(:region).try(:country) comment&.author&.address&.primary&.city&.region &.country http://www.reactionface.info/face/troll-face
  21. http://www.jasondemakis.com/wp-content/uploads/2015/09/yoda-there-is-no-try1.png