Skip to content

Latest commit

 

History

History
77 lines (64 loc) · 3.11 KB

rails.md

File metadata and controls

77 lines (64 loc) · 3.11 KB

Rails

  • Keep README.md always updated
  • Grouping and order on top of ActiveRecord models:
class ModelName < ApplicationRecord
  # includes
  include ModuleName

  # enums
  enum type: [:a, :b, :c, :d]

  # relationships
  belongs_to :parent
  has_many :children

  # attributes
  attr_accessor :fieldname

  # validations
  validates :name, presence: true

  # scopes
  scope :deleted, -> { where(deleted: true) }

  # callbacks
  before_save :do_something
end
  • Custom code or PORO1 (validators, services, etc):
    • Add application specific code under app/
    • Add code that can be extracted for use in other projects to lib/
      • Ask the question: Can I use this code in my Tinder clone? If yes, it goes in lib

Database

  • Ensure db:migrate runs properly
  • Ensure db:rollback runs properly
  • Ensure db:seed runs properly (They get outdated fast!). Alternatively, provide a way to seed a newcomer's project.
  • Ensure painless turnovers

"Service" Objects

  • A service object is a PORO that models business logic so that it can be reused across multiple callers (for example from controllers, rake tasks, background jobs and even other services!).
  • Name these classes as NounVerber
    • CreditCardCharger
  • Expose a constructor that sets up initialization configuration
    • CreditCardCharger.new(processor: :braintree)
  • Expose an instance method named call and send data parameters to this
    • CreditCardCharger.new(processor: braintree).call('4111111111111111','123','11/28')
    • Call returns a Result object which can encapsulate the success, errors and instance
      result = CreditCardCharger.new(processor: :Braintree).call(card_details)
      if result.success?
        Rails.log("Successful trans: #{result.transaction}")
      else
        Rails.error("Error in transaction: #{result.errors}")
      end
    
  • Keep in app/services folder (see custom code above)
  • When initializing services, pass in instances

ActiveJob

  • Keep jobs in app/jobs
  • Keep job perform parameters to a minimum. Ideally, pass in [model].id as parameter and query within the job. (This also allows the job to fail if record is not found)

Other POROs

  • Put code into logical containers. Don't be afraid to add folders to your app/ folder as this is autoloaded by default.
    • app/decorators
    • app/utilities
    • app/composers
  • Check out Design Patterns in Ruby

1 PORO = Plain Old Ruby Object.

The distinction between a PORO (which stands for Plain Old Ruby Object) and a not-PORO is not a technical one. All objects are technically Ruby object. Instead, the term PORO is sometimes used when talking about large frameworks like Rails which tend to use "big", "complex" objects like ActiveRecord models for much of its logic. These large objects tend to contain a large amount of logic and defined behavior.

-via Holger Just/Stack Overflow