39
Rails 3 Extra-hints

Rails 3 hints

Embed Size (px)

DESCRIPTION

Some hints extracted from my experience porting rails 2 applications to rails 3

Citation preview

Page 1: Rails 3 hints

Rails 3Extra-hints

Page 2: Rails 3 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...

Page 3: Rails 3 hints

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")

Page 4: Rails 3 hints

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}, ...

Page 5: Rails 3 hints

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)

Page 6: Rails 3 hints

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

Page 7: Rails 3 hints

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

Page 8: Rails 3 hints

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/

Page 9: Rails 3 hints

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

Page 10: Rails 3 hints

Rails 3 > Action Mailer

- template variables are not passed explicitly to the render

@vars[:books] = ...body {:vars => @vars ...}#=>@books = ...

Page 11: Rails 3 hints

● 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

Page 12: Rails 3 hints

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".)

Page 13: Rails 3 hints

(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

Page 14: Rails 3 hints

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| %>

Page 15: Rails 3 hints

● 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

Page 16: Rails 3 hints

● 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

Page 17: Rails 3 hints

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....

Page 18: Rails 3 hints

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, ... }

Page 19: Rails 3 hints

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

Page 20: Rails 3 hints

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

Page 21: Rails 3 hints

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)

Page 22: Rails 3 hints

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 => ...

Page 23: Rails 3 hints

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)

Page 24: Rails 3 hints

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.

Page 25: Rails 3 hints

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

Page 26: Rails 3 hints

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à!

Page 27: Rails 3 hints

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)

Page 28: Rails 3 hints

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

Page 29: Rails 3 hints

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!

Page 30: Rails 3 hints

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)

Page 31: Rails 3 hints

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?

Page 32: Rails 3 hints

Delayed Job

● called differently: ○ send_later :bang #=> delay.bang

Page 33: Rails 3 hints

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)

Page 34: Rails 3 hints

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

Page 35: Rails 3 hints

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={}|...}

Page 36: Rails 3 hints

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 : {}

Page 37: Rails 3 hints

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 ‘’

Page 38: Rails 3 hints

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.

Page 39: Rails 3 hints

Questions?

Check the documentation, and more importantly, pay attention to your development log noise.

More Hints?