Features covered¶ ↑
-
Generators
-
Engines - Spree (state_machine)
-
Rake tasks - Nokogiri
-
Assets + precompiling
-
Migrations
-
Deface (app/overrides) + Decorator
-
ActiveRecord associations
-
RSpec/Capybara + Rails Testing
-
FactoryGirl, FFaker
-
Rails/Ruby versions
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¶ ↑
Ruby = 'attr_accessor' for instances only
Rails += 'cattr_accessor' for class access 'mattr_accessor' for module access http://stackoverflow.com/questions/185573/what-is-mattr-accessor-in-a-rails-module
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¶ ↑
-
$ rails g model Email email:string label:string contact:references
Migration¶ ↑
-
$ rails g migration CreateContact first_name:string last_name:string
-
$ rails g migration AddEmailIDToContacts email:references
(Not necessary with generated model above which includes FK)
(Child object hold “pointer” to Parent to reduce coupling, cf linked data structures not using DB)
-
$ rails g migration AddFlashToContacts flash:string
$ 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¶ ↑
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:
-
Scopes are chainable class methods are not
A scope will always return a relation, whereas our simple class method implementation will not.
-
Scopes are extensible
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:
Sprockets: Compiles assets in specified paths together and places them in target path eg 'public/assets' Tilt: Template engine like allows files like '.scss' and '.erb'
Manifest files
(See http://guides.rubyonrails.org/asset_pipeline.html) In JavaScript files, Sprockets directives begin with '//=' Multiple Sass files should use '@import' rather than Sprockets '*=' directives Sprockets directives cause Sass files to exist in their own scope so variables + mixins ONLY AVAILABLE in defining doc
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
-
classify
Create a class name from a plural table name
-
constantize
Find declared constant with a string
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:
-
$ gem dependency json –reverse-dependencies