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. 1.

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

    nils Karol Galanciak - full-stack developer at Twitter: @Azdaroth
  2. 4.

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

    Hash#[] name = params[:name] name = params.fetch(:name)
  3. 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)
  4. 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)
  5. 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 %>
  6. 9.
  7. 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
  8. 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
  9. 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
  10. 15.

    4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value * percentage end end
  11. 16.

    4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value.to_d * percentage end end
  12. 17.

    4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value.to_s.to_d * percentage end end
  13. 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
  14. 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