Ruby on Rails: Validation, Queries, Layouts, and Styling in Rails April 15th, 2015
- You can also validate any object, not just ActiveRecord objects
- Declare rules using validation helpers (e.g. validates :title, presence: true … which validates that the title is there)
- Lifecycle methods – save, update, and create
- “Bang” method variants raise exception if object is not valid (e.g. save!, create!, update!)
- include ActiveModel::Validations
- Validations populate the errors object
- Conditional validation: validate only if (or unless) certain conditions are true … unless: “pages.blank?”
- You can bypass validation manually by passing validate: false argument … book.save(validate: false) … useful in specific use cases, e.g. save a “draft” object for a user to return and complete later
- Optional fields with validation when filled out … validates :ssn, length: { is: 8 }, allow_blank: true
- Create custom validation class that extends ActiveModel::Validator and use validates_with
- You can also define methods in your class for specialized validation
- Add directly to the errors object
- Register them using validate method
class Person < ActiveRecord::Base validate :birthday_cannot_be_in_the_future def birthday_cannot_be_in_the_future if birthday.present? && birthday > Date.today errors.add(:birthday, "can't be in the future") end end end
- The Flash is a way to send messages to users like “Your order was placed” or “The item was removed from your cart”
- Standard types
- notice
- alert
- flash
- Standard types
- Sessions store small amounts of data for each user that persist across requests (in cookies)
- Stored in a hash
- session[:user_id] = user.id
- user = User.find(session[:user_id])
- Stored in a hash
- Active Record Query Interface
- Main concept: ActiveRecord::Relation
- Power comes from chaining multiple relations together and lazy evaluation of SQL queries
- SQL = Structured Query Language and is used in all relational databases
- From an earlier class… Book.all, Book.count, Book.find(42), Book.find_by(title: ‘The Hobbit’)…
- These execute SQL queries immediately and do not return relations
- You can chain multiple AND conditions … Book.where(‘author = ?’, ‘Tolkien’).where(‘pages < ?’, 400)
- SQL injection alert!…
- NEVER DO THIS… EVER… SERIOUSLY… Account.where(“number = ‘#{params[:acct_number]}'”)
- What happens if the acct_number parameter (presumably from a malicious user) is ‘ OR ” = ‘?
- SELECT “accounts”.* FROM “accounts” WHERE (number = ” OR ” = ”) … DOH!
- Use anonymous parameters with ? to avoid SQL injections … Book.where(‘author = ? and pages < ?’, ‘Tolkien’, 400) = SELECT “books”.* FROM “books” WHERE (author = ‘Tolkien’ and pages < 400)
- Scopes encapsulate common queries
- Return ActiveRecord::Relation … so they can be chained together just like where, order, limit, etc.
- Similar to defining class methods in a model
- Scopes handle some edge cases
- Scopes can make the intent more clear
- Use find_by_sql if you need to do very complicated custom SQL queries not supported by ActiveRecord
- Layouts reside in app/views/layouts
- An application has an common layout named application.html.erb
- yield inserts content from the view rendered by the controller
- content_for produces content to be inserted into a “named” yield
- Partials encapsulate separate content (header, footer, navigation bar, flashes, etc.)
- The Asset Pipeline is the mechanism in Rails used to manage assets in different deployment environments (e.g. development, production)
- 3 main features
- Concatenate assets
- Compress/minify assets
- Abstract the asset implementation language
- 3 main features
- Asset “Fingerprinting” for cache busting in production
- Manifests determine which assets to include and contain directives which tell Rails which files to require in order to build concatenated assets…
- require_self requires code in the current file
- require_tree recursively requires all files in a directory and subdirectories
- require_directory does not recurse
- When assets are precompiled for production mode, they are placed in public/assets by default
- Kaminari gem provides easy pagination
- Add gem ‘kaminari’ and ‘kaminari-bootstrap’ to Gemfile
- gem ‘kaminari’
- gem ‘kaminari-bootstrap’, ‘~> 3.0.1’
- Then bin/bundle install
- Run rails g kaminari:config (g is short for generate)
- Override config.default_per_page option in kaminari_config.rb
- Add route for friendly URLS
resources :books do get 'page/:page', :action => :index, :on => :collection end
- Call page method in controller
- Book.order(:title).page(params[:page])
- Populate in the view for index.html.erb
- <%= paginate @books %>
- Add gem ‘kaminari’ and ‘kaminari-bootstrap’ to Gemfile