Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

karol.galanciak

January 13, 2016
Tweet

More Decks by karol.galanciak

Other Decks in Programming

Transcript

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

    nils Karol Galanciak - full-stack developer at Twitter: @Azdaroth
  2. 1. Use right set of methods 1. Prefer Hash#fetch over

    Hash#[] name = params[:name] name = params.fetch(:name)
  3. 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. 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 protected]" }, 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. 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. 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
  7. 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
  8. 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
  9. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

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

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

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