{"id":3703,"date":"2015-04-15T19:10:07","date_gmt":"2015-04-15T23:10:07","guid":{"rendered":"http:\/\/webninjataylor.com\/library\/?p=3703"},"modified":"2015-04-22T19:45:29","modified_gmt":"2015-04-22T23:45:29","slug":"ruby-on-rails-validation-queries-layouts-and-styling-in-rails","status":"publish","type":"post","link":"https:\/\/webninjataylor.com\/library\/ruby-on-rails-validation-queries-layouts-and-styling-in-rails\/","title":{"rendered":"Ruby on Rails: Validation, Queries, Layouts, and Styling in Rails"},"content":{"rendered":"<ul>\n<li>You can also validate any object, not just ActiveRecord objects<\/li>\n<li>Declare rules using validation helpers\u00a0(e.g. validates :title, presence: true &#8230; which validates that the title is there)<\/li>\n<li>Lifecycle methods &#8211; save, update, and create<\/li>\n<li>&#8220;Bang&#8221; method variants raise exception if object is not valid (e.g. save!, create!, update!)<\/li>\n<li><span class=\"code\">include ActiveModel::Validations<\/span><\/li>\n<li>Validations populate the errors object<\/li>\n<li>Conditional validation: validate only if (or unless) certain conditions are true &#8230;\u00a0<span class=\"code\">unless: &#8220;pages.blank?&#8221;<\/span><\/li>\n<li>You can bypass validation manually by passing <span class=\"code\">validate: false<\/span> argument &#8230;\u00a0<span class=\"code\">book.save(validate: false)<\/span> &#8230; useful in specific use cases, e.g. save a &#8220;draft&#8221; object for a user to return and complete later<\/li>\n<li>Optional fields with validation when filled out &#8230;\u00a0<span class=\"code\">validates :ssn, length: { is: 8 }, allow_blank: true<\/span><\/li>\n<li>Create custom validation class that extends <span class=\"code\">ActiveModel::Validator<\/span> and use <span class=\"code\">validates_with<\/span><\/li>\n<li>You can also define methods in your class for specialized validation\n<ul>\n<li>Add directly to the <span class=\"code\">errors<\/span> object<\/li>\n<li>Register them using <span class=\"code\">validate<\/span> method\n<pre>class Person &lt; ActiveRecord::Base\r\n  validate :birthday_cannot_be_in_the_future\r\n\r\n  def birthday_cannot_be_in_the_future\r\n    if birthday.present? &amp;&amp; birthday &gt; Date.today\r\n      errors.add(:birthday, \"can't be in the future\")\r\n    end\r\n  end\r\nend\r\n<\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li>The Flash is a way to send messages to users\u00a0like &#8220;Your order was placed&#8221; or &#8220;The item was removed from your cart&#8221;\n<ul>\n<li>Standard types\n<ul>\n<li><span class=\"code\">notice<\/span><\/li>\n<li><span class=\"code\">alert<\/span><\/li>\n<li><span class=\"code\">flash<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Sessions store small amounts of data for each user that persist across requests (in cookies)\n<ul>\n<li>Stored in a hash\n<ul>\n<li><span class=\"code\">session[:user_id] = user.id<\/span><\/li>\n<li><span class=\"code\">user = User.find(session[:user_id])<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Active Record Query Interface\n<ul>\n<li>Main concept: ActiveRecord::Relation<\/li>\n<li>Power comes from chaining multiple relations together and lazy evaluation of SQL queries<\/li>\n<\/ul>\n<\/li>\n<li>SQL = Structured Query Language and is used in all relational databases<\/li>\n<li>From an earlier class&#8230;\u00a0Book.all,\u00a0Book.count,\u00a0Book.find(42),\u00a0Book.find_by(title: &#8216;The Hobbit&#8217;)&#8230;\n<ul>\n<li>These execute SQL queries immediately and do <strong>not<\/strong> return relations<\/li>\n<\/ul>\n<\/li>\n<li>You can chain multiple AND conditions &#8230;\u00a0<span class=\"code\">Book.where(&#8216;author = ?&#8217;, &#8216;Tolkien&#8217;).where(&#8216;pages &lt; ?&#8217;, 400)<\/span><\/li>\n<li>SQL injection alert!&#8230;\n<ul>\n<li>NEVER DO THIS&#8230; EVER&#8230; SERIOUSLY&#8230;\u00a0<span class=\"code\">Account.where(&#8220;number = &#8216;#{params[:acct_number]}'&#8221;)<\/span><\/li>\n<li>What happens if the acct_number parameter (presumably from a malicious user) is <span class=\"code\">&#8216; OR &#8221; = &#8216;<\/span>?<\/li>\n<li><span class=\"code\">SELECT &#8220;accounts&#8221;.* FROM &#8220;accounts&#8221;\u00a0<\/span><span style=\"line-height: 1.5;\"><span class=\"code\">WHERE (number = &#8221; OR &#8221; = &#8221;)<\/span> &#8230; DOH!<\/span><\/li>\n<\/ul>\n<\/li>\n<li><strong>Use anonymous\u00a0parameters with <span class=\"code\">?<\/span> to avoid SQL injections<\/strong> &#8230; Book.where(&#8216;author = ? and pages &lt; ?&#8217;, &#8216;Tolkien&#8217;, 400) =\u00a0SELECT &#8220;books&#8221;.* FROM &#8220;books&#8221; WHERE (author = &#8216;Tolkien&#8217; and pages &lt; 400)<\/li>\n<li>Scopes encapsulate common queries\n<ul>\n<li>Return ActiveRecord::Relation\u00a0&#8230; so they can be chained together just like where, order, limit, etc.<\/li>\n<li>Similar to defining class methods in a model\n<ul>\n<li>Scopes handle some edge cases<\/li>\n<li>Scopes can make the intent more clear<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Use <span class=\"code\">find_by_sql<\/span> if you need to do very complicated custom SQL queries not supported by ActiveRecord<\/li>\n<li>Layouts reside in app\/views\/layouts<\/li>\n<li>An application has an common layout named application.html.erb\n<ul>\n<li><span class=\"code\">yield<\/span> inserts content from the view rendered by the controller<\/li>\n<li><span class=\"code\">content_for<\/span> produces content to be inserted into a &#8220;named&#8221; yield<\/li>\n<\/ul>\n<\/li>\n<li>Partials encapsulate separate content (header, footer, navigation bar, flashes, etc.)<\/li>\n<li>The Asset Pipeline is the mechanism in Rails used to manage assets in different deployment environments (e.g. development, production)\n<ul>\n<li>3 main features\n<ul>\n<li>Concatenate assets<\/li>\n<li>Compress\/minify assets<\/li>\n<li>Abstract the asset implementation language<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Asset &#8220;Fingerprinting&#8221; for cache busting in production<\/li>\n<li>Manifests determine which assets to include and contain directives which tell Rails which files to require in order to build concatenated assets&#8230;\n<ul>\n<li><span class=\"code\">require_self<\/span> requires code in the current file<\/li>\n<li><span class=\"code\">require_tree<\/span> recursively requires all files in a directory and subdirectories<\/li>\n<li><span class=\"code\">require_directory<\/span> does not recurse<\/li>\n<\/ul>\n<\/li>\n<li>When assets are precompiled for production mode, they are placed in public\/assets by default<\/li>\n<li>Kaminari gem provides easy pagination\n<ul>\n<li>Add gem &#8216;kaminari&#8217; and &#8216;kaminari-bootstrap&#8217; to <strong>Gemfile<\/strong>\n<ul>\n<li><span class=\"code\">gem &#8216;kaminari&#8217;<\/span><\/li>\n<li><span class=\"code\">gem &#8216;kaminari-bootstrap&#8217;, &#8216;~&gt; 3.0.1&#8217;<\/span><\/li>\n<\/ul>\n<\/li>\n<li>Then <span class=\"code\">bin\/bundle <strong>install<\/strong><\/span><\/li>\n<li>Run <span class=\"code\">rails g kaminari:<strong>config<\/strong><\/span> (g is short for generate)\n<ul>\n<li>Override config.default_per_page option in kaminari_config.rb<\/li>\n<\/ul>\n<\/li>\n<li>Add <strong>route<\/strong> for friendly URLS\n<pre>resources :books do\r\n  get 'page\/:page', :action =&gt; :index, :on =&gt; :collection\r\nend\r\n<\/pre>\n<\/li>\n<li>Call page method in <strong>controller<\/strong>\n<ul>\n<li><span class=\"code\">Book.order(:title).page(params[:page])<\/span><\/li>\n<\/ul>\n<\/li>\n<li>Populate in the <strong>view<\/strong> for index.html.erb\n<ul>\n<li><span class=\"code\">&lt;%= paginate @books %&gt;<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>You can also validate any object, not just ActiveRecord objects Declare rules using validation helpers\u00a0(e.g. validates :title, presence: true &#8230; which validates that the title is there) Lifecycle methods &#8211; save, update, and create &#8220;Bang&#8221; method variants raise exception if object is not valid (e.g. save!, create!, update!) include ActiveModel::Validations Validations populate the errors object [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[144],"tags":[152],"class_list":["post-3703","post","type-post","status-publish","format-standard","hentry","category-web-shots","tag-ruby"],"_links":{"self":[{"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/posts\/3703","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/comments?post=3703"}],"version-history":[{"count":29,"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/posts\/3703\/revisions"}],"predecessor-version":[{"id":3802,"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/posts\/3703\/revisions\/3802"}],"wp:attachment":[{"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/media?parent=3703"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/categories?post=3703"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webninjataylor.com\/library\/wp-json\/wp\/v2\/tags?post=3703"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}