Rails 3 hints
-
Upload
tiago-cardoso -
Category
Technology
-
view
952 -
download
0
description
Transcript of Rails 3 hints
Rails 3Extra-hints
Summary● Rails 3
○ Deprecations for Rails 4○ ActionMailer○ Ajax in Rails 3○ General...
● Formtastic (2.2)○ Deprecations for V.3○ Custom Inputs
● Acts as Paranoid● Will Paginate● Rspec● ViewModels● Inherited Resources● Delayed Job● Ruby 1.9● Assorted...
Rails 3 > Deprecations
Plugins will cease to exist
Solutions:● get the gem● insert plugin folder in /lib● insert somewhere else and bundle them in your gemfile:
gem "view_models", "=2.0.1", :path => File.join(File.dirname(__FILE__), "/vendor/modified_gems/view_models-2.0.1")
Rails 3 > Deprecations
ActiveRecord Validations
Rails 2validates_presence_of :attrvalidates_length_of :attr, :within => 2..60validates_uniqueness_of :attr, :scope => [:assoc_id]
…Rails 3
validates :attr, :presence => true, :length => {:within => 2..60}, :uniqueness => {:scope => :assoc_id}, ...
Rails 3 > Deprecations
AR queries● Rails 2
ClassName.all(:conditions => ["blbla.id = ?", 1])...● Rails 3
○ Still supported, but it is just translating to ARel. Support in Rails 4 is still unknown.
ClassName.where("blbla.id = ?", 1)
Rails 3 > Deprecations
table names● Rails 2:ClassName < ActiveRecord::Base
set_table_name :bang...
end
● Rails 3:ClassName < ActiveRecord::Base
self.table_name = :bang...
end
Rails 3 > Deprecations
● link_to :confirm optionRails2: link_to ... :confirm => “Sure?” Rails3: link_to ... :data => {:confirm => “Sure?”}
● url helper accept :format option => :html, :js, :json, :xml, etc...
● render accepts two extra options: :formats and :handlerstemplate: app/views/homepage/index.html.hamlname: :index / “index” / “homepage/index” … (extension out!)formats: :htmlhandlers: :hamlrender :index, :formats => :html, :handlers => :haml
if called in respond_to html block:render :index, :handlers => :hamlif defined in environment that template engine is :haml:render :index
Rails 3 > Deprecations
composed_of will be probably removed. Still not officially deprecated, but:
http://blog.plataformatec.com.br/2012/06/about-the-composed_of-removal/
Rails 3 > ActionMailer
● mail delivery: created before delivered:
Mailer.deliver_registry #=> Mailer.registry.deliver
● template extensions changed:
template_name.text.plain.haml #=> template_name.text.hamltemplate_name.text.html.haml #=> template_name.html.haml
Rails 3 > Action Mailer
- template variables are not passed explicitly to the render
@vars[:books] = ...body {:vars => @vars ...}#=>@books = ...
● avoid "include_something" scopes -> just use ARel method “includes” directly
ClassName.include_books #=> ClassName.includes(:books)
● RJS is gone○ when writing ".js" templates, every ruby block
inserted has to be explicitly escaped (escape_javascript)
RAILS_ENV, RAILS_ROOT, RAILS_DEFAULT_LOGGER (Strings)Rails.env, Rails.root, Rails.logger (Pathnames)
Rails 3 > General
Rails 3 > General
● Rails.root can be joined directly
File.join(Rails.root,‘bang’) #=> Rails.root.join(‘bang’)
(note: Rails.root is from type Pathname. Quoting the documentation: "All functionality from File, FileTest, and some from Dir and FileUtils is included, in an unsurprising way. It is essentially a facade for all of these, and more".)
(Previous Rails 2 bug)
Ajax (xhr) != "Script" (Content-Type)● JQuery’s $.get() does an asynchronous html request. Rails will build the
response body in html format (assuming type is not given to $.get)
● JQuery’s $.getScript() does an asynchronous script request. Rails will build the response in the js format
● JQuery’s $.getJSON() does an asynchronous json request. Rails will build the response in the json format
● ...
● you get the idea
● if you want to test if the request was asynchronous in the controller, use request.xhr?
Rails 3 - General
Rails 3 > General
● rendering flush logic changed: template calls with blocks that render something have to be marked with “=” ; others with “-” (Haml notation):
in ERB:<%= form_for(...) do %>...<% @elements.each do |element| %>
● URL helpers: clear distinction from url elements on explicit assignment
○ host : only host! ■ restorm.dev:3000 -> host is restorm.dev
○ subdomain : only subdomain!■ choco.restorm.com -> subdomain is choco■ us.members.restorm.com -> subdomain is us.
members○ port : only port!
■ restorm.dev:3000 -> port is 3000○ user ; password; ... you get the idea
Rails 3 > General
● ActiveRecord errors handled differently:errors.on(:attr) #=> errors[:attr]
● full asset paths: compute_asset_url(“/images/image.jpg”) #=> image_path(“/images/image.jpg”)
● form calls where we want to define the variable name explicitly works differently in Rails 3:form_for :song, elem #=> form_for elem, :as => :song
● Array “random” function was removed; use “sample” instead:[1, 2, 3].random #=> [1, 2, 3].sample
Rails 3 > General
Rails 3 > General
Arel and Scopes
● everything is concatenated, not only the conditions (as in Rails 2)
● avoid defining a condition like select(“table_name.*”); it does that already by default
● (related to above) avoid defining “select” calls in scopes whenever possible; everytime you concatenate it with another “select” call, they will be joined “SELECT *, id FROM...“ #=> WRONG!
● same thing for “order” calls, “group” calls, etc....
Rails 3 > General
Arel and Scopes
● Rails 3 ARel bug: if you have a “group” call in your ARel/scope definition and call “count” at the end, it will not return an Integer, but an OrderedHash (?), careful with that
Rightclearing::Song.count #=> 15269Rightclearing::Song.group_by(:album_title).count #=> {""=>2410, " Little pieces for guitars and other instruments - Part I"=>15, " so black, so bright-instrumental"=>6, ... }
Rails 3 > General
ModulesRails 2:
module Bla
def self.included(base)
base.has_many ….
base.send :include, InstanceMethods
base.extend ClassMethods
end
module ClassMethods
end
module InstanceMethods
def bang
end
end
end
Rails 3 > General
ModulesRails 3:
module Bla
extend ActiveSupport::Concern
included do
has_many
# include InstanceMethods, but, it does this implicitly
extend ClassMethods
end
module ClassMethods
end
def bang
end
end
Rails 3 > General● included from Concern module executes the code in the
block in the scope of the element where the module is included (no more need for the “send :included” call that breaks visibility);
● different order of inclusion (may be an issue in certain cases where we have hacked stuff for inherited resources and other gems...)
● functions defined directly in the module will be instance methods implicitly in the class where the module is included (no more need for the explicit module InstanceMethods)
Formtastic > Deprecations
● explicit value for input now inside input_htmlf.input :attr, :value => 3 f.input :attr, :input_html => { :value => 3 }
● input for dates is now called :date_select● buttons defined differently:
f.buttons do... #=> f.actions do ...f.commit_button #=> f.action :submit #=> <input type=submit...../>f.commit_button :button_html =>... #=> f.action :submit, :as => :button, :button_html => ...
Formtastic - Hints
● nested “inputs” calls on the same builder do not work as before anymore:f.inputs do
%lif.inputs do
….WRONG!
● Notes:
● does not produce invalid HTML as before (good)
● produces nevertheless HTML, though unexpected (so so...)
● does not produce warning message (bad)
Formtastic - Hints
● if an attribute is of type Integer, the resulting input will be of type number (HTML5)
Main Issues with this:○ Some JS code was dependent of the input type
being "text"
Ways to avoid it:○ Provide a context to the element instead of
depending of it directly; mark elements with a class.
Formtastic - Custom Inputs
● Input Structure changed - Focus on modularity
● All Standard Inputs include the Base Module● All Standard Inputs define the to_html which
renders the input● Separate Modules defining input validations,
labelling, content wrapping, errors, collection, etc...
● Everything can be overwritten/redefined
Formtastic - Custom Inputs
Country Select Box
● Inherits From SelectInput, because it is a select box
● Additionally caches the countries and calls them in the "collection" method, which is used by the parent to render the select box
...Et Voilà!
Acts As Paranoid
● Different Gem● Different Developers● Different code-basis! ● More or less the same API
note: in order to use :with_deleted option for associations in a class which is not paranoid itself, include ActsAsParanoid::Associations (see change_tracking/change.rb model for an implementation)
Will Paginate
● array pagination is not available implicitly; if you need it, you’ll have to require ‘will_paginate/array’ explicitly in the file using it
● https://github.com/mislav/will_paginate/wiki/Backwards-incompatibility
RSpec
● ‘double’ recommended instead of ‘mock’● Factory(:element) returns a stubbed model.
They neither have an id anymore nor they can be saved anymore.
● One cannot stub :id calls:
○ Factory(:model, :id => 23) is not valid!
ViewModels
● module to include for view_model_for access changed:
include ViewModels::Helpers::Railsinclude ViewModels::Helpers::Mapping
● ViewModels gem is not being developed further... use a new gem in RC instead? (possible candidate: decorators)
Inherited Resources
● loading helpers on server start; not reloading them on update; everytime you change something in the helpers, you’ll have to restart the server (Major downer...)
● Deprecated; Gem creator recommends using the new Rails 3 controllers ; consider removal in RC?
Delayed Job
● called differently: ○ send_later :bang #=> delay.bang
Ruby 1.9
● the new file character encoding system. new to anyone? in new files that might not have been marked with the utf8 tag, please do.# -*- encoding : utf-8 -*-
● to_a removed from the Object APIsomething.to_a => Array(something)
Ruby 1.9
● “require” calls must be made using the full path (or relative to the file where it is being called)
● when you return something from a Proc, you are not returning it from the Proc, but instead from the scope where the Proc is being executed ○ no scope is returning now
Ruby 1.9
● Array#to_s works differently:○ Ruby 1.8 - [1, 2].to_s #=> “12”○ Ruby 1.9 - [1.2].to_s #=> “[1, 2]”○ use.join instead
● procs now support splat arguments and default values for them:○ proc {|id, args*, opts={}|...}
Assorted
● forms that involve upload or possible upload (more explicitly contain files, non-ASCII data, and binary data) should be marked as multipart.
● in cases where the method arguments are defined with a pointer (“def func(*args)”) and we want to extract the options hash from the last argument:opts = args.extract_options!opts = args.last.is_a?(Hash) ? args.pop : {}
Assorted
● if there are functions that need to be shared between the controller and its respective template rendering scope (templates, helpers), use the helper_method method and define it only one time in the controller.
● Avoid inclusion of helpers in controllers; either they are helpers and therefore should support the rendering, or they are controller mixins that are responsible for handling controller code (and may define helper functions using the helper_method method mentioned above)
● use always t(“a.b.c.d”) instead of t(:d => :scope => [:a, :b, :c]) it is better to look for..and use always “” and not ‘’
Assorted
● Avoid writing explicit scopes (unless you really really have too...)
Class.where(“table_name.attribute = 1”) Class.where(:attribute => 1)
● Why? ○ ARel sanitizes everything ○ ARel gets the table names and attribute names from
the table structure by itself○ (very important!) ARel quotes the table name,
attribute name and value all by himself (something we seldom do).
● Implicitly protects us from SQL injection, table name changing and usage of SQL reserved words.
Questions?
Check the documentation, and more importantly, pay attention to your development log noise.
More Hints?