Features covered


1 - Run-time changes

Ruby allows monkey-patching using the 'eval' method

Spree has Deface to change Views at run-time
Decorator is a design pattern to change things at run-time, it is used in Spree to change models

2 - Rails extension of Ruby getter/setter definition

guides.rubyonrails.org/active_support_core_extensions.html#class-attributes

Ruby = 'attr_accessor' for instances only

Rails += 'cattr_accessor' for class access
         'mattr_accessor' for module access

3 - Respond_to

'ActionController.respond_to'
  The passed block gets called with the 'responder' argument (that gets renamed to whatever, often 'format')
  This arg then gets put into the Ruby Pipe, "|...|", and is the function prototype of the hooked code,
  generated at run-time.

http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to

4 - Putting ruby in coffeescript

Add '.erb' onto filename extension

Then put <% debugger %> tags in code

5 - Rails Generators

“Since Rails 3.0, generators are built on top of Thor”

http://guides.rubyonrails.org/generators.html

“public task :name” allows private methods in parent accessed from child as commands

http://rdoc.info/github/erikhuda/thor/master/Thor/Base/ClassMethods#public_command-instance_method
eg 'railties-4.0.2/lib/rails/generators/rails/app/app_generator.rb:163'

Model

Migration

$ bundle exec rake db:migrate

6 - Rails Integration testing

Rails automatically loads all fixtures from 'test/fixtures'

Starts by deleting from DB table based on filename eg 'spree_ordersHIDE.yml' looks for table 'spree_ordersHIDE'

7 - RSpec requests

End-to-end request/response black box testing based on 'ActionDispatch::Integration::Runner'

https://github.com/rspec/rspec-rails

8 - FactoryGirl vs Fixtures

Higher level than fixtures, at the Rails object level

Similar to RSpec stubs

Abstract wrapper around Rails objects that focuses only on the feature of relevance

Test DB normalization (redundant info is moved into the factory)

Can create unique values using sequences
Includes Rails associations if necessary

Create = DB object (default for 'Factory()')
Build = Memory object

9 - Paperclip

Creates DB migration and updates Model using 'has_attached_file'

Resizes images using 'ImageMagick'

Can use validation methods in Controller

Paperclips default path is 'RAILS_ROOT/public/system'

Change by ':url' + ':path' options to 'has_attached_file' method
Options changed in Spree admin-configuration-image settings

Spree:

edit_admin_product_image GET /admin/products/:product_id/images/:id/edit(.:format) spree/admin/images#edit
  'backend/app/controllers/spree/admin/resource_controller.rb'
  'backend/app/views/spree/admin/images/edit.html.erb'
  'core/app/models/spree/image.rb'

psql=# select * from spree_assets where id=57;
matches 'RAILS_ROOT/public/spree/products/57'
BUT FOR PRODUCT ID 59 ie "BURNT ORANGE"!

WHAT'S THE MAPPING???  PRODUCT ID ALWAYS SEEMS TO BE 2 MORE THAN ASSET ID...que???
$ rails c -e production
  almond = Spree::Product.find_by_id(72)
  almond.images[0].id
   => 70

spreeBSC_production=# select id from spree_products where name='HONEY';
  67
spreeBSC_production=# select id from spree_variants where product_id=67 and is_master='t';
  445
spreeBSC_production=# select id,attachment_file_name from spree_assets where viewable_id=445;
  65 | open-uri20140414-388-b7g4vp

THEREFORE:

HONEY (ID 67) uses image 'RAILS_ROOT/public/spree/products/65 in the production DB

10 - Get previous value of attribute after update

Append “_was” to attribute name

Rails 2 - ActiveRecord::Dirty
Rails 4 - ActiveModel::Dirty

In Rails 3 the non-database functionality of Active Record is extracted out into Active Model.

11 - Send units to Integer

(See 'ruby.txt' for details about the 'send' method)

Rails adds some extra time and date functionality to Ruby:

ActiveSupport::Duration

$ irb
  > 1.send("minutes")
    undefined method 'minutes' for 1:Fixnum
$ rails c
  > 1.send("minutes")
   => 60 seconds

12 - ActiveRecord

Polymorphic associations

Abstract association or interface

guides.rubyonrails.org/association_basics.html#polymorphic-associations

"You can think of a polymorphic belongs_to declaration as setting up an interface that any other model can use."

Scoping

guides.rubyonrails.org/active_record_querying.html#scopes

api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html

"A scope represents a narrowing of a database query, such as 
 where(color: :red).select('shirts.*').includes(:washing_instructions)."

'ActiveRecord::scope' method for defining a class method that has a SQL query with specified values.

class Post < ActiveRecord::Base
  scope :published, where(status: 'published')
  scope :draft, -> { where(status: 'draft') } 
end

'published' condition evaluated when class first loaded
'draft' is lazy evaluated when called.

Rails 4 requires that you declare scopes with a callable object (which prevents time condition problems)

class Post < ActiveRecord::Base
  scope :published_last_week, where('published_at >= ?', 1.week.ago)
end

Scopes vs Class methods:

blog.plataformatec.com.br/2013/02/active-record-scopes-vs-class-methods/

“I personally tend to use scopes when the logic is very small, for simple where/order clauses, and class methods when it involves a bit more complexity. I also tend to rely more on scopes when doing extensions”

Foreign Keys and Referential Integrity

robots.thoughtbot.com/referential-integrity-with-foreign-keys

Referential Integrity states implied relationships among data should be enforced

Rails allows to easily create implied relationships BUT NOTHING TO ENFORCE IT!

class User < ActiveRecord::Base
  has_many :posts
  validates :name, presence: true
end

class Post < ActiveRecord::Base
  belongs_to :user
  validates :user, presence: true
end

We can delete users but the post remains which will result in an error when posts are listed!

Can be solved by:

class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
end

Problem returns if user ActiveRecord.where() method to find and delete a batch without instantiating objects:

user_ids = CSV.read(csv_path).flatten
User.where(id: user_ids).delete_all

Since 'delete_all' doesn't instantiate objects so no 'after_destroy' callbacks fired (which hooks 'dependent' option)

DB much better at handling referential integrity than Rails!

Before Rails 4.2 then this needed the Foreigner gem

Run the following migration:

def change
  add_foreign_key :posts, :users
end

Which creates following SQL:

ALTER TABLE 'posts'
ADD CONSTRAINT 'posts_user_id_fk'
FOREIGN KEY ('user_id') REFERENCES 'users'(id);

However 'user_id' of NULL is allowed so need presence validations and NOT NULL constraints

Now DB prevents user being deleted with any connected posts so need CASCADING DELETES in DB:

def change
  remove_foreign_key :posts, :users
  add_foreign_key :posts, :users, dependent: :delete

  # or in the upcoming native support in Rails 4.2
  # add_foreign_key :posts, :users, on_delete: :cascade
end

Which creates following SQL:

ALTER TABLE 'posts'
ADD CONSTRAINT 'posts_user_id_fk'
FOREIGN KEY ('user_id') REFERENCES 'users'(id)
ON DELETE CASCADE;

We can now remove 'dependent' option from User (since handled by DB)

class User
  # Old association:
  # has_many :posts, dependent: :destroy

  has_many :posts
end

Use 'immigrant' Gem to automatically add foreign key constraints

$ rails generate immigration add_foreign_keys

This will lead to probs on production data so download copy of production data,
then alter data + fix actions causing invalid data (which now will result in errors)

Polymorphic associations are maintained by Rails so LOGIC REMAINS IN RAILS APP to maintain RI.

13 - Asset pipeline

In Rails 3.1, the asset pipeline is enabled by default.

Comprised of:

Manifest files (See guides.rubyonrails.org/asset_pipeline.html)

14 - Rails 4.0

weblog.rubyonrails.org/2013/6/25/Rails-4-0-final/

25 June 2013

If you haven't already, now is a good time to upgrade to Ruby 2.0 as well. Rails 5+ will require Ruby 2.0, 
so you might as well get a head start.

15 - Rails 4.2

weblog.rubyonrails.org/2014/12/19/Rails-4-2-final/

19 Dec 2014

Active Job

Active Job is an adapter layer on top of queuing systems like Resque, Delayed Job, Sidekiq, and more.
You can write your jobs to Active Job, and they'll run on all these queues with no changes.

Adequate Record

Adequate Record for Active Record.  A lot of common queries are now no less than twice as fast in Rails 4.2!

Foreign Keys

The migration DSL gets 'add_foreign_key' and 'remove_foreign_key'
Foreign key support starts out as an exclusive to the MySQL and PostgreSQL adapters.

Ruby 2.2+

Rails 4.2 also marks the last big release in the 4.x series.

Rails 5.0 will target Ruby 2.2+ exclusively.
There are a bunch of optimizations coming in Ruby 2.2 but most importantly for Rails, symbols are going to be 
garbage collected. 
This means we can shed a lot of weight related to juggling strings 
It also means that we can convert fully to keyword arguments

16 - ActiveSupport::Inflector

(9/4/16)

apidock.com/rails/ActiveSupport/Inflector

17 - Railtie

(2/6/16)

Every major component of Rails is a Railtie (eg Action Controller, Action View, Active Record)

Makes Rails absent of any component hooks
Allows other components to be used in place of Rails defaults

Abstract class which follows the Singleton pattern

Abstract class is partially completed Interface

www.idyllic-software.com/blog/understanding-railtie-and-mountable-rails-engine/

18 - Gems/Bundler

Installed gems:

19 - Named yield + 'content_for'

(26/9/16)

guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method

20 - Caching

(15/10/16)

guides.rubyonrails.org/caching_with_rails.html

api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html

> Rails.cache.clear

21 - Rake

spree_auth:admin:create

(15/10/16)

22 - Bundler

(27/10/16)

Wrapper around RubyGems for handling version dependencies:

www.youtube.com/watch?v=4_TqAMWbzfw