Table of Contents

1. Rails Environment and Configuration

1.2. Startup and Application Settings

Uruchamiając środowisko Railsów (na przykład za pomocą polecenia rails server), najpierw przetwarzane są trzy pliki:

require 'rubygems'
 
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
 
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
require File.expand_path('../boot', __FILE__)
 
require 'rails/all'
 
if defined?(Bundler)
  # If you precompile assets before deploying to production, use this line
  Bundler.require *Rails.groups(:assets => %w(development test))
  # If you want your assets lazily compiled in production, use this line
  # Bundler.require(:default, :assets, Rails.env)
end
 
module TestApp
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
 
    # Custom directories with classes and modules you want to be autoloadable.
    # config.autoload_paths += %W(#{config.root}/extras)
 
    # Only load the plugins named here, in the order given (default is alphabetical).
    # :all can be used as a placeholder for all plugins not explicitly named.
    # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
 
    # Activate observers that should always be running.
    # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
 
    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    # config.time_zone = 'Central Time (US & Canada)'
 
    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de
 
    # Configure the default encoding used in templates for Ruby 1.9.
    config.encoding = "utf-8"
 
    # Configure sensitive parameters which will be filtered from the log file.
    config.filter_parameters += [:password]
 
    # Enable the asset pipeline
    config.assets.enabled = true
 
    # Version of your assets, change this if you want to expire all your assets
    config.assets.version = '1.0'
  end
end
# Load the rails application
require File.expand_path('../application', __FILE__)
 
# Initialize the rails application
TestApp::Application.initialize!

1.2.1. application.rb

require "active_model/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_view/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
config.generators do |g|
  g.template_engine :haml
  g.test_framework :rspec, :fixture => false

1.2.2. Initializers

ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'pensum', 'pensa'
end

1.2.3. Dodatkowa konfiguracja

5. Working with Active Record

5.3. Defining Attributes

5.3.1. Default Attribute Values

Zwracanie kategorii, a w gdy jest ona nil, zwrócenie n/a:

class TimesheetEntry < ActiveRecord::Base
  def category
    read_attribute(:category) || 'n/a'
  end
end

5.3.2. Serialized Attributes

class User < ActiveRecord::Base
  serialize :preferences, Hash
end
def preferences
  read_attribute(:preferences) || write_attribute(:preferences, {})
end

5.4. CRUD: Creating, Reading, Updating, Deleting

5.4.1. Creating New Active Record Instances

>> c = Client.new
=> #<Client id: nil, name: nil, code: nil>
>> c.new_record?
=> true
>> c.persisted?
=> false
c = Client.create(:name => "sQbase", :code => "SQB")

5.4.2. Reading Active Record Objects

# Pobranie obiektu o danym id
first_girl = Girl.find(1)
 
# Pobranie ostatniego obiektu
last_girl_standing = Girl.last
 
# Pobranie wszystkich (w00t!) dziewcząt
sqbells_life = Girl.all
 
# Przedziały również i tu działają
v3rts_life = Girl.find([1, 2])

5.4.3. Reading and Writing Attributes

>> first_girl.name
=> "Antonina Louis"
def name
  read_attribute(:name).reverse
end
 
# irb
>> first_girl.name
=> "siuoL aninotnA"
 
# trzeba uważać na nieskończoną rekurencję!
def name
  self.name.reverse
end
 
# irb
>> first_girl.name
SystemStackError: stack level too deep [...]
first_girl['name']
first_girl[:name]
>> first_girl.attributes
=> {"name"=>"Antonina Louis", "phone"=>"n/a", "id"=>1}
>> atts = first.girl.attributes
>> atts["name"] = "Kasia Vitton"
=> "Kasia Vitton"
>> first_girl.attributes
=> {"name"=>"Antonina Louis", "phone"=>"n/a", "id"=>1}

5.4.4. Accessing and Manipulating Attributes Before They Are Typecast

5.4.7. Dynamic Attribute-Based Finders

Girl.find_by_height(176)
 
Girl.find_by_height_and_weight(176, 60)
 
# to samo, z pomocą klauzuli where
Girl.where("height = ? AND weight = ?", height, weight)
Girl.order("cuteness").find_all_by_height(176)
Girl.find_or_create_by_height_and_weight_and_name("176", "60", "Zuzanna")

5.4.8. Dynamic Scopes

Girl.scoped_by_height("176").order(:cuteness)
 
# irb
>> Girl.methods.include?("scoped_by_height")
=> true
>> Girl.methods.include?("scoped_by_weight")
=> false

5.4.9. Custom SQL Queries

5.4.10. Query Cache

User.cache do
  puts User.first
  puts User.first
  puts User.first
end
 
# development.log
User Load (1.0ms)  SELECT * FROM users LIMIT 1
CACHE (0.0ms)  SELECT * FROM users LIMIT 1
CACHE (0.0ms)  SELECT * FROM users LIMIT 1
SELECT foo FROM bar WHERE id = 1
SELECT foo FROM bar WHERE id = 1 LIMIT 1

5.4.13. Updating a Particular Instance

5.4.14. Updating Specific Attributes

5.4.15. Convenience Updaters

5.4.16. Touching Records

class User < ActiveRecord::Base
  belongs_to :client, :touch => true
end
 
# irb
>> user.touch #=> user.client.touch jest również uruchamiane

5.4.17. Controlling Access to Attributes

class Girl < ActiveRecord::Base
  attr_protected = :phone_number
end
 
girl = Girl.new(:name => "Zuzanna", :phone_number => "605 945 344")
girl.phone_number # => nil
 
girl.attributes = { "phone_number" => "605 945 344" }
girl.phone_number # => nil
 
# atrybut można ustawić tylko tak
girl.phone_number = "605 945 344"
girl.phone_number  # => "605 945 344"

5.4.18. Readonly Attributes

class Girl < ActiveRecord::Base
  attr_readonly :annoying_level
end

5.4.19. Deleting and Destroying

Girl.delete(1)
Girl.delete([2, 3])

5.5. Database Locking

5.5.1. Optimistic Locking

5.5.2. Pessimistic Locking

5.6. Where Clauses

5.6.1. where (*conditions)

5.6.2. order(*clauses)

5.6.3. limit(number) i offset(number)

User.limit(10).offset(10)

5.6.8. includes(*associations)

5.6.10. readonly

5.6.11. exists?

5.6.12. arel_table

7. Active Record Associations

7.1. The Association Hierarchy

7.2. One-to-Many Relationships

9. Advanced Active Record

9.1. Scopes

class Timesheet < ActiveRecord::Base
  scope :submitted, where(:submitted => true)
  scope :underutilized, where('total_hours < 40')
class User < ActiveRecord::Base
  scope :delinquent, lambda{where('timesheets_updated_at < ?', 1.week.ago)}

9.1.1. Scope Parameters

13. Session Management

sqbell@sqbell-netbook:~$ curl 10.0.0.10:3000 -I

HTTP/1.1 200 OK 
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "492b3c7c9fd2d950e1f2ada5a46651b3"
Cache-Control: max-age=0, private, must-revalidate
X-Runtime: 0.100905
Content-Length: 0
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Fri, 30 Sep 2011 15:45:08 GMT
Connection: Keep-Alive
Set-Cookie: _depot_session=BAh7CEkiD3Nlc3Npb25faWQGOgZFRkkiJWE1N2I1NWQ0NTdkY2UzN2E2MTkxNTM4ZDRlZTE5Zj
Y0BjsAVEkiDGNvdW50ZXIGOwBGaQZJIhBfY3NyZl90b2tlbgY7AEZJIjFxeE1DOHhBMFVqN2RjMGZ0NCtOdWp4blRrelRSQUJHSW1
zY3NuRGdqT1g4PQY7AEY%3D--9cddc91db772a3ab182baf74f504ed390a165569; path=/; HttpOnly

13.1. What to Store in the Session

13.3. Storage Mechanisms

13.3.1. Active Record Session Store

MyApplication::Application.config.session_store :active_record_store

13.3.2. Memcache Session Storage

17. Caching and Performance

17.1. View Caching

Mamy trzy rodzaje cache'owania widoków:

17.1.2. Page Caching

17.1.3. Action Caching

17.1.4. Fragment Caching

17.1.5. Wygasanie zawartości pamięci podręcznej

17.1.6. Automatic Cache Expiry with Sweepers

17.1.9. Cache Storage

Mamy do wykorzystanie trzy różne opcje przechowywania pamięci podręcznej:

17.2. General Caching

17.2.1. Eliminating Extra Database Lookups

17.3. Control Web Caching

17.4. ETags