diff options
Diffstat (limited to 'guides')
127 files changed, 1412 insertions, 1350 deletions
diff --git a/guides/Rakefile b/guides/Rakefile index 84e18e0972..4116e6f9cc 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -30,7 +30,7 @@ namespace :guides do unless Kindlerb.kindlegen_available? abort "Please run `setupkindlerb` to install kindlegen" end - unless `convert` =~ /convert/ + unless /convert/.match?(`convert`) abort "Please install ImageMagick" end ENV["KINDLE"] = "1" diff --git a/guides/assets/images/rails4_features.png b/guides/assets/images/4_0_release_notes/rails4_features.png Binary files differindex ac73f05cf7..ac73f05cf7 100644 --- a/guides/assets/images/rails4_features.png +++ b/guides/assets/images/4_0_release_notes/rails4_features.png diff --git a/guides/assets/images/akshaysurve.jpg b/guides/assets/images/akshaysurve.jpg Binary files differdeleted file mode 100644 index cfc3333958..0000000000 --- a/guides/assets/images/akshaysurve.jpg +++ /dev/null diff --git a/guides/assets/images/belongs_to.png b/guides/assets/images/association_basics/belongs_to.png Binary files differindex 2b8c1d52ea..2b8c1d52ea 100644 --- a/guides/assets/images/belongs_to.png +++ b/guides/assets/images/association_basics/belongs_to.png diff --git a/guides/assets/images/habtm.png b/guides/assets/images/association_basics/habtm.png Binary files differindex 7e508cc1a6..7e508cc1a6 100644 --- a/guides/assets/images/habtm.png +++ b/guides/assets/images/association_basics/habtm.png diff --git a/guides/assets/images/has_many.png b/guides/assets/images/association_basics/has_many.png Binary files differindex 36ccf9f0f6..36ccf9f0f6 100644 --- a/guides/assets/images/has_many.png +++ b/guides/assets/images/association_basics/has_many.png diff --git a/guides/assets/images/has_many_through.png b/guides/assets/images/association_basics/has_many_through.png Binary files differindex 9e9caabd73..9e9caabd73 100644 --- a/guides/assets/images/has_many_through.png +++ b/guides/assets/images/association_basics/has_many_through.png diff --git a/guides/assets/images/has_one.png b/guides/assets/images/association_basics/has_one.png Binary files differindex c29c6b9c59..c29c6b9c59 100644 --- a/guides/assets/images/has_one.png +++ b/guides/assets/images/association_basics/has_one.png diff --git a/guides/assets/images/has_one_through.png b/guides/assets/images/association_basics/has_one_through.png Binary files differindex fdf13286c4..fdf13286c4 100644 --- a/guides/assets/images/has_one_through.png +++ b/guides/assets/images/association_basics/has_one_through.png diff --git a/guides/assets/images/polymorphic.png b/guides/assets/images/association_basics/polymorphic.png Binary files differindex d630db9e01..d630db9e01 100644 --- a/guides/assets/images/polymorphic.png +++ b/guides/assets/images/association_basics/polymorphic.png diff --git a/guides/assets/images/credits_pic_blank.gif b/guides/assets/images/credits_pic_blank.gif Binary files differdeleted file mode 100644 index a6b335d0c9..0000000000 --- a/guides/assets/images/credits_pic_blank.gif +++ /dev/null diff --git a/guides/assets/images/fxn.png b/guides/assets/images/fxn.png Binary files differdeleted file mode 100644 index 733d380cba..0000000000 --- a/guides/assets/images/fxn.png +++ /dev/null diff --git a/guides/assets/images/getting_started/rails_welcome.png b/guides/assets/images/getting_started/rails_welcome.png Binary files differindex 44f89ec8de..88efe34a9d 100644 --- a/guides/assets/images/getting_started/rails_welcome.png +++ b/guides/assets/images/getting_started/rails_welcome.png diff --git a/guides/assets/images/getting_started/routing_error_no_route_matches.png b/guides/assets/images/getting_started/routing_error_no_route_matches.png Binary files differdeleted file mode 100644 index 08c54f921f..0000000000 --- a/guides/assets/images/getting_started/routing_error_no_route_matches.png +++ /dev/null diff --git a/guides/assets/images/header_backdrop.png b/guides/assets/images/header_backdrop.png Binary files differdeleted file mode 100644 index 81f4d91774..0000000000 --- a/guides/assets/images/header_backdrop.png +++ /dev/null diff --git a/guides/assets/images/icons/README b/guides/assets/images/icons/README deleted file mode 100644 index 09da77fc86..0000000000 --- a/guides/assets/images/icons/README +++ /dev/null @@ -1,5 +0,0 @@ -Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook -icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency -from the Jimmac icons to get round MS IE and FOP PNG incompatibilities. - -Stuart Rackham diff --git a/guides/assets/images/icons/callouts/1.png b/guides/assets/images/icons/callouts/1.png Binary files differdeleted file mode 100644 index c5d02adcf4..0000000000 --- a/guides/assets/images/icons/callouts/1.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/10.png b/guides/assets/images/icons/callouts/10.png Binary files differdeleted file mode 100644 index fe89f9ef83..0000000000 --- a/guides/assets/images/icons/callouts/10.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/11.png b/guides/assets/images/icons/callouts/11.png Binary files differdeleted file mode 100644 index 3b7b9318e7..0000000000 --- a/guides/assets/images/icons/callouts/11.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/12.png b/guides/assets/images/icons/callouts/12.png Binary files differdeleted file mode 100644 index 7b95925e9d..0000000000 --- a/guides/assets/images/icons/callouts/12.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/13.png b/guides/assets/images/icons/callouts/13.png Binary files differdeleted file mode 100644 index 4b99fe8efc..0000000000 --- a/guides/assets/images/icons/callouts/13.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/14.png b/guides/assets/images/icons/callouts/14.png Binary files differdeleted file mode 100644 index dbde9ca749..0000000000 --- a/guides/assets/images/icons/callouts/14.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/15.png b/guides/assets/images/icons/callouts/15.png Binary files differdeleted file mode 100644 index 70e4bba615..0000000000 --- a/guides/assets/images/icons/callouts/15.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/2.png b/guides/assets/images/icons/callouts/2.png Binary files differdeleted file mode 100644 index 8c57970ba9..0000000000 --- a/guides/assets/images/icons/callouts/2.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/3.png b/guides/assets/images/icons/callouts/3.png Binary files differdeleted file mode 100644 index 57a33d15b4..0000000000 --- a/guides/assets/images/icons/callouts/3.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/4.png b/guides/assets/images/icons/callouts/4.png Binary files differdeleted file mode 100644 index f061ab02b8..0000000000 --- a/guides/assets/images/icons/callouts/4.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/5.png b/guides/assets/images/icons/callouts/5.png Binary files differdeleted file mode 100644 index b4de02da11..0000000000 --- a/guides/assets/images/icons/callouts/5.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/6.png b/guides/assets/images/icons/callouts/6.png Binary files differdeleted file mode 100644 index 0e055eec1e..0000000000 --- a/guides/assets/images/icons/callouts/6.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/7.png b/guides/assets/images/icons/callouts/7.png Binary files differdeleted file mode 100644 index 5ead87d040..0000000000 --- a/guides/assets/images/icons/callouts/7.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/8.png b/guides/assets/images/icons/callouts/8.png Binary files differdeleted file mode 100644 index cb99545eb6..0000000000 --- a/guides/assets/images/icons/callouts/8.png +++ /dev/null diff --git a/guides/assets/images/icons/callouts/9.png b/guides/assets/images/icons/callouts/9.png Binary files differdeleted file mode 100644 index 0ac03602f6..0000000000 --- a/guides/assets/images/icons/callouts/9.png +++ /dev/null diff --git a/guides/assets/images/icons/caution.png b/guides/assets/images/icons/caution.png Binary files differdeleted file mode 100644 index 7227b54b32..0000000000 --- a/guides/assets/images/icons/caution.png +++ /dev/null diff --git a/guides/assets/images/icons/example.png b/guides/assets/images/icons/example.png Binary files differdeleted file mode 100644 index a0e855befa..0000000000 --- a/guides/assets/images/icons/example.png +++ /dev/null diff --git a/guides/assets/images/icons/home.png b/guides/assets/images/icons/home.png Binary files differdeleted file mode 100644 index e70e164522..0000000000 --- a/guides/assets/images/icons/home.png +++ /dev/null diff --git a/guides/assets/images/icons/important.png b/guides/assets/images/icons/important.png Binary files differdeleted file mode 100644 index bab53bf3aa..0000000000 --- a/guides/assets/images/icons/important.png +++ /dev/null diff --git a/guides/assets/images/icons/next.png b/guides/assets/images/icons/next.png Binary files differdeleted file mode 100644 index a158832725..0000000000 --- a/guides/assets/images/icons/next.png +++ /dev/null diff --git a/guides/assets/images/icons/note.png b/guides/assets/images/icons/note.png Binary files differdeleted file mode 100644 index 62eec7845f..0000000000 --- a/guides/assets/images/icons/note.png +++ /dev/null diff --git a/guides/assets/images/icons/prev.png b/guides/assets/images/icons/prev.png Binary files differdeleted file mode 100644 index 8a96960422..0000000000 --- a/guides/assets/images/icons/prev.png +++ /dev/null diff --git a/guides/assets/images/icons/tip.png b/guides/assets/images/icons/tip.png Binary files differdeleted file mode 100644 index a5316d318f..0000000000 --- a/guides/assets/images/icons/tip.png +++ /dev/null diff --git a/guides/assets/images/icons/up.png b/guides/assets/images/icons/up.png Binary files differdeleted file mode 100644 index 6cac818170..0000000000 --- a/guides/assets/images/icons/up.png +++ /dev/null diff --git a/guides/assets/images/icons/warning.png b/guides/assets/images/icons/warning.png Binary files differdeleted file mode 100644 index 72a8a5d873..0000000000 --- a/guides/assets/images/icons/warning.png +++ /dev/null diff --git a/guides/assets/images/oscardelben.jpg b/guides/assets/images/oscardelben.jpg Binary files differdeleted file mode 100644 index 9f3f67c2c7..0000000000 --- a/guides/assets/images/oscardelben.jpg +++ /dev/null diff --git a/guides/assets/images/radar.png b/guides/assets/images/radar.png Binary files differdeleted file mode 100644 index 421b62b623..0000000000 --- a/guides/assets/images/radar.png +++ /dev/null diff --git a/guides/assets/images/rails_logo_remix.gif b/guides/assets/images/rails_logo_remix.gif Binary files differdeleted file mode 100644 index 58960ee4f9..0000000000 --- a/guides/assets/images/rails_logo_remix.gif +++ /dev/null diff --git a/guides/assets/images/csrf.png b/guides/assets/images/security/csrf.png Binary files differindex a8123d47c3..a8123d47c3 100644 --- a/guides/assets/images/csrf.png +++ b/guides/assets/images/security/csrf.png diff --git a/guides/assets/images/session_fixation.png b/guides/assets/images/security/session_fixation.png Binary files differindex e009484f09..e009484f09 100644 --- a/guides/assets/images/session_fixation.png +++ b/guides/assets/images/security/session_fixation.png diff --git a/guides/assets/images/tab_yellow.png b/guides/assets/images/tab_yellow.png Binary files differdeleted file mode 100644 index 053c807d28..0000000000 --- a/guides/assets/images/tab_yellow.png +++ /dev/null diff --git a/guides/assets/images/vijaydev.jpg b/guides/assets/images/vijaydev.jpg Binary files differdeleted file mode 100644 index fe5e4f1cb4..0000000000 --- a/guides/assets/images/vijaydev.jpg +++ /dev/null diff --git a/guides/assets/javascripts/guides.js b/guides/assets/javascripts/guides.js index e4d25dfb21..e39ac239cd 100644 --- a/guides/assets/javascripts/guides.js +++ b/guides/assets/javascripts/guides.js @@ -1,53 +1,54 @@ -$.fn.selectGuide = function(guide) { - $("select", this).val(guide); -}; - -var guidesIndex = { - bind: function() { - var currentGuidePath = window.location.pathname; - var currentGuide = currentGuidePath.substring(currentGuidePath.lastIndexOf("/")+1); - $(".guides-index-small"). - on("change", "select", guidesIndex.navigate). - selectGuide(currentGuide); - $(document).on("click", ".more-info-button", function(e){ - e.stopPropagation(); - if ($(".more-info-links").is(":visible")) { - $(".more-info-links").addClass("s-hidden").unwrap(); - } else { - $(".more-info-links").wrap("<div class='more-info-container'></div>").removeClass("s-hidden"); - } - }); - $("#guidesMenu").on("click", function(e) { - $("#guides").toggle(); - return false; +(function() { + "use strict"; + + this.syntaxhighlighterConfig = { autoLinks: false }; + + this.wrap = function(elem, wrapper) { + elem.parentNode.insertBefore(wrapper, elem); + wrapper.appendChild(elem); + } + + this.unwrap = function(elem) { + var wrapper = elem.parentNode; + wrapper.parentNode.replaceChild(elem, wrapper); + } + + this.createElement = function(tagName, className) { + var elem = document.createElement(tagName); + elem.classList.add(className); + return elem; + } + + document.addEventListener("DOMContentLoaded", function() { + var guidesMenu = document.getElementById("guidesMenu"); + var guides = document.getElementById("guides"); + + guidesMenu.addEventListener("click", function(e) { + e.preventDefault(); + guides.classList.toggle("visible"); }); - $(document).on("click", function(e){ - e.stopPropagation(); - var $button = $(".more-info-button"); - var element; - // Cross browser find the element that had the event - if (e.target) element = e.target; - else if (e.srcElement) element = e.srcElement; + var guidesIndexItem = document.querySelector("select.guides-index-item"); + var currentGuidePath = window.location.pathname; + guidesIndexItem.value = currentGuidePath.substring(currentGuidePath.lastIndexOf("/") + 1); - // Defeat the older Safari bug: - // http://www.quirksmode.org/js/events_properties.html - if (element.nodeType === 3) element = element.parentNode; + guidesIndexItem.addEventListener("change", function(e) { + window.location = e.target.value; + }); - var $element = $(element); + var moreInfoButton = document.querySelector(".more-info-button"); + var moreInfoLinks = document.querySelector(".more-info-links"); - var $container = $element.parents(".more-info-container"); + moreInfoButton.addEventListener("click", function(e) { + e.preventDefault(); - // We've captured a click outside the popup - if($container.length === 0){ - $container = $button.next(".more-info-container"); - $container.find(".more-info-links").addClass("s-hidden").unwrap(); + if (moreInfoLinks.classList.contains("s-hidden")) { + wrap(moreInfoLinks, createElement("div", "more-info-container")); + moreInfoLinks.classList.remove("s-hidden"); + } else { + moreInfoLinks.classList.add("s-hidden"); + unwrap(moreInfoLinks); } }); - }, - navigate: function(e){ - var $list = $(e.target); - var url = $list.val(); - window.location = url; - } -}; + }); +}).call(this); diff --git a/guides/assets/javascripts/jquery.min.js b/guides/assets/javascripts/jquery.min.js deleted file mode 100644 index 93adea19fd..0000000000 --- a/guides/assets/javascripts/jquery.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.7.2 jquery.com | jquery.org/license */ -(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"<!doctype html>":"")+"<html><body>"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&f.type(b)==="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bZ(a,c,d,e,"*",g));return l}function bY(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bB(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?1:0,g=4;if(d>0){if(c!=="border")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,"padding"+bx[e]))||0),c==="margin"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0;return d+"px"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,"padding"+bx[e]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+"px"}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?b.outerHTML=a.outerHTML:c!=="input"||a.type!=="checkbox"&&a.type!=="radio"?c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute("_submit_attached"),b.removeAttribute("_change_attached"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d=="object"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?n(g):h==="function"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement("div"),q=c.documentElement;p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="<div "+n+"display:block;'><div style='"+t+"0;display:block;overflow:hidden;'></div></div>"+"<table "+n+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="<table><tr><td style='"+t+"0;display:none'></td><td>t</td></tr></table>",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="<div style='width:5px;'></div>",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,"parsedAttrs")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf("data-")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,"parsedAttrs",!0)}}return m}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!";return f.access(this,function(c){if(c===b){m=this.triggerHandler("getData"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler("setData"+e,d),f.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,""),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( -a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!=="click")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9||d===11){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")[\\s/>]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f -.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:"GET",global:!1,url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1></$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]==="<table>"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,"script")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName("script"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\([^)]*\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,bu=/^([\-+])=([\-+.\de]+)/,bv=/^margin/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Top","Right","Bottom","Left"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),(e===""&&f.css(d,"display")==="none"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,"olddisplay",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(ct("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&"expand"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),q?(f._data(this,"toggle"+i,q==="show"?"hide":"show"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?"":"px"),p!=="px"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]==="-="?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct("show",1),slideUp:ct("hide",1),slideToggle:ct("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,"fxshow"+e.prop)===b&&(e.options.hide?f._data(e.elem,"fxshow"+e.prop,e.start):e.options.show&&f._data(e.elem,"fxshow"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf("margin")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position==="fixed")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position==="relative"||j.position==="static")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position==="fixed"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
\ No newline at end of file diff --git a/guides/assets/javascripts/responsive-tables.js b/guides/assets/javascripts/responsive-tables.js index 8554a1343b..24906dddeb 100644 --- a/guides/assets/javascripts/responsive-tables.js +++ b/guides/assets/javascripts/responsive-tables.js @@ -1,43 +1,50 @@ -$(document).ready(function() { +(function() { + "use strict"; + var switched = false; - $("table").not(".syntaxhighlighter").addClass("responsive"); + + // For old browsers + var each = function(node, callback) { + var array = Array.prototype.slice.call(node); + for(var i = 0; i < array.length; i++) callback(array[i]); + } + + each(document.querySelectorAll(":not(.syntaxhighlighter)>table"), function(element) { + element.classList.add("responsive"); + }); + var updateTables = function() { - if (($(window).width() < 767) && !switched ){ + if (document.documentElement.clientWidth < 767 && !switched) { switched = true; - $("table.responsive").each(function(i, element) { - splitTable($(element)); - }); - return true; - } - else if (switched && ($(window).width() > 767)) { + each(document.querySelectorAll("table.responsive"), splitTable); + } else { switched = false; - $("table.responsive").each(function(i, element) { - unsplitTable($(element)); - }); + each(document.querySelectorAll(".table-wrapper table.responsive"), unsplitTable); } - }; - - $(window).load(updateTables); - $(window).bind("resize", updateTables); - - - function splitTable(original) - { - original.wrap("<div class='table-wrapper' />"); - - var copy = original.clone(); - copy.find("td:not(:first-child), th:not(:first-child)").css("display", "none"); - copy.removeClass("responsive"); - - original.closest(".table-wrapper").append(copy); - copy.wrap("<div class='pinned' />"); - original.wrap("<div class='scrollable' />"); - } - - function unsplitTable(original) { - original.closest(".table-wrapper").find(".pinned").remove(); - original.unwrap(); - original.unwrap(); - } - -}); + } + + document.addEventListener("DOMContentLoaded", updateTables); + window.addEventListener("resize", updateTables); + + var splitTable = function(original) { + wrap(original, createElement("div", "table-wrapper")); + + var copy = original.cloneNode(true); + each(copy.querySelectorAll("td:not(:first-child), th:not(:first-child)"), function(element) { + element.style.display = "none"; + }); + copy.classList.remove("responsive"); + + original.parentNode.append(copy); + wrap(copy, createElement("div", "pinned")) + wrap(original, createElement("div", "scrollable")); + } + + var unsplitTable = function(original) { + each(document.querySelectorAll(".table-wrapper .pinned"), function(element) { + element.parentNode.removeChild(element); + }); + unwrap(original.parentNode); + unwrap(original); + } +}).call(this); diff --git a/guides/assets/stylesheets/main.css b/guides/assets/stylesheets/main.css index b27776745a..cd355b1d1a 100644 --- a/guides/assets/stylesheets/main.css +++ b/guides/assets/stylesheets/main.css @@ -33,6 +33,13 @@ pre, code { overflow: auto; color: #222; } + +p code { + background: #eee; + border-radius: 2px; + padding: 1px 3px; +} + pre, tt, code { white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ @@ -70,7 +77,7 @@ table { } table th, table td { - padding: 0.25em 1em; + padding: 9px 10px; border: 1px solid #CCC; border-collapse: collapse; } @@ -79,7 +86,6 @@ table th { border-bottom: 2px solid #CCC; background: #EEE; font-weight: bold; - padding: 0.5em 1em; } img { @@ -265,8 +271,6 @@ body { } } -#extraCol {display: none;} - #footer { padding: 2em 0; background: #222 url(../images/footer_tile.gif) repeat-x; @@ -410,6 +414,10 @@ a, a:link, a:visited { padding-top: 2em; } +#guides.visible { + display: block !important; +} + #guides dt, #guides dd { font-weight: normal; font-size: 0.722em; @@ -555,8 +563,6 @@ h6 { font-size: 1.2857em; padding: 0.125em 0 0.25em 0; margin-bottom: 0; - /*background: url(../images/book_icon.gif) no-repeat left top; - padding: 0.125em 0 0.25em 28px;*/ } @media screen and (max-width: 480px) { @@ -633,7 +639,9 @@ div.code_container { margin: 0.25em 0 1.5em 0; } -.note code, .info code, .todo code {border:none; background: none; padding: 0;} +.note code, .info code, .todo code { + background: #fff; +} #mainCol ul li { list-style:none; @@ -665,10 +673,8 @@ div.code_container { visibility: hidden; } -.clearfix {display: inline-block;} * html .clearfix {height: 1%;} .clearfix {display: block;} -.clear { clear:both; } /* Same bottom margin for special boxes than for regular paragraphs, this way intermediate whitespace looks uniform. */ @@ -696,9 +702,6 @@ div.important p, div.caution p, div.warning p, div.note p, div.info p { /* Foundation v2.1.4 http://foundation.zurb.com */ /* Artfully masterminded by ZURB */ -table th { font-weight: bold; } -table td, table th { padding: 9px 10px; text-align: left; } - /* Mobile */ @media only screen and (max-width: 767px) { table.responsive { margin-bottom: 0; } diff --git a/guides/assets/stylesheets/print.css b/guides/assets/stylesheets/print.css index bdc8ec948d..6280422469 100644 --- a/guides/assets/stylesheets/print.css +++ b/guides/assets/stylesheets/print.css @@ -4,7 +4,7 @@ /* Modified January 31, 2009 --------------------------------------- */ -body, .wrapper, .note, .info, code, #topNav, .L, .R, #frame, #container, #header, #navigation, #footer, #feature, #mainCol, #subCol, #extraCol, .content {position: static; text-align: left; text-indent: 0; background: White; color: Black; border-color: Black; width: auto; height: auto; display: block; float: none; min-height: 0; margin: 0; padding: 0;} +body, .wrapper, .note, .info, code, #topNav, .L, .R, #frame, #container, #header, #navigation, #footer, #feature, #mainCol, #subCol, .content {position: static; text-align: left; text-indent: 0; background: White; color: Black; border-color: Black; width: auto; height: auto; display: block; float: none; min-height: 0; margin: 0; padding: 0;} body { background: #FFF; diff --git a/guides/assets/stylesheets/responsive-tables.css b/guides/assets/stylesheets/responsive-tables.css deleted file mode 100644 index f5fbcbf948..0000000000 --- a/guides/assets/stylesheets/responsive-tables.css +++ /dev/null @@ -1,50 +0,0 @@ -/* Foundation v2.1.4 http://foundation.zurb.com */ -/* Artfully masterminded by ZURB */ - -/* -------------------------------------------------- - Table of Contents ------------------------------------------------------ -:: Shared Styles -:: Page Name 1 -:: Page Name 2 -*/ - - -/* ----------------------------------------- - Shared Styles ------------------------------------------ */ - -table th { font-weight: bold; } -table td, table th { padding: 9px 10px; text-align: left; } - -/* Mobile */ -@media only screen and (max-width: 767px) { - - table { margin-bottom: 0; } - - .pinned { position: absolute; left: 0; top: 0; background: #fff; width: 35%; overflow: hidden; overflow-x: scroll; border-right: 1px solid #ccc; border-left: 1px solid #ccc; } - .pinned table { border-right: none; border-left: none; width: 100%; } - .pinned table th, .pinned table td { white-space: nowrap; } - .pinned td:last-child { border-bottom: 0; } - - div.table-wrapper { position: relative; margin-bottom: 20px; overflow: hidden; border-right: 1px solid #ccc; } - div.table-wrapper div.scrollable table { margin-left: 35%; } - div.table-wrapper div.scrollable { overflow: scroll; overflow-y: hidden; } - - table td, table th { position: relative; white-space: nowrap; overflow: hidden; } - table th:first-child, table td:first-child, table td:first-child, table.pinned td { display: none; } - -} - -/* ----------------------------------------- - Page Name 1 ------------------------------------------ */ - - - - -/* ----------------------------------------- - Page Name 2 ------------------------------------------ */ - - diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb index 7fc85e636a..e8b6ad19dd 100644 --- a/guides/bug_report_templates/action_controller_gem.rb +++ b/guides/bug_report_templates/action_controller_gem.rb @@ -13,7 +13,7 @@ gemfile(true) do git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Activate the gem you are reporting the issue against. - gem "rails", "5.2.0.rc1" + gem "rails", "5.2.0" end require "rack/test" diff --git a/guides/bug_report_templates/active_job_gem.rb b/guides/bug_report_templates/active_job_gem.rb index 6b30a7d446..720b7e9c51 100644 --- a/guides/bug_report_templates/active_job_gem.rb +++ b/guides/bug_report_templates/active_job_gem.rb @@ -13,7 +13,7 @@ gemfile(true) do git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Activate the gem you are reporting the issue against. - gem "activejob", "5.2.0.rc1" + gem "activejob", "5.2.0" end require "minitest/autorun" diff --git a/guides/bug_report_templates/active_record_gem.rb b/guides/bug_report_templates/active_record_gem.rb index fabc2a2382..c0d705239b 100644 --- a/guides/bug_report_templates/active_record_gem.rb +++ b/guides/bug_report_templates/active_record_gem.rb @@ -13,7 +13,7 @@ gemfile(true) do git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Activate the gem you are reporting the issue against. - gem "activerecord", "5.2.0.rc1" + gem "activerecord", "5.2.0" gem "sqlite3" end diff --git a/guides/bug_report_templates/active_record_migrations_gem.rb b/guides/bug_report_templates/active_record_migrations_gem.rb index ca9987f956..f47cf08766 100644 --- a/guides/bug_report_templates/active_record_migrations_gem.rb +++ b/guides/bug_report_templates/active_record_migrations_gem.rb @@ -13,7 +13,7 @@ gemfile(true) do git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Activate the gem you are reporting the issue against. - gem "activerecord", "5.2.0.rc1" + gem "activerecord", "5.2.0" gem "sqlite3" end diff --git a/guides/bug_report_templates/generic_gem.rb b/guides/bug_report_templates/generic_gem.rb index 7a55d7c660..0935354bf4 100644 --- a/guides/bug_report_templates/generic_gem.rb +++ b/guides/bug_report_templates/generic_gem.rb @@ -13,7 +13,7 @@ gemfile(true) do git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Activate the gem you are reporting the issue against. - gem "activesupport", "5.2.0.rc1" + gem "activesupport", "5.2.0" end require "active_support" diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb index 7205f37be7..c83538ad48 100644 --- a/guides/rails_guides/generator.rb +++ b/guides/rails_guides/generator.rb @@ -141,32 +141,34 @@ module RailsGuides puts "Generating #{guide} as #{output_file}" layout = @kindle ? "kindle/layout" : "layout" - File.open(output_path, "w") do |f| - view = ActionView::Base.new( - @source_dir, - edge: @edge, - version: @version, - mobi: "kindle/#{mobi}", - language: @language - ) - view.extend(Helpers) - - if guide =~ /\.(\w+)\.erb$/ - # Generate the special pages like the home. - # Passing a template handler in the template name is deprecated. So pass the file name without the extension. - result = view.render(layout: layout, formats: [$1], file: $`) - else - body = File.read("#{@source_dir}/#{guide}") - result = RailsGuides::Markdown.new( - view: view, - layout: layout, - edge: @edge, - version: @version - ).render(body) - - warn_about_broken_links(result) - end + view = ActionView::Base.new( + @source_dir, + edge: @edge, + version: @version, + mobi: "kindle/#{mobi}", + language: @language + ) + view.extend(Helpers) + + if guide =~ /\.(\w+)\.erb$/ + return if %w[_license _welcome layout].include?($`) + + # Generate the special pages like the home. + # Passing a template handler in the template name is deprecated. So pass the file name without the extension. + result = view.render(layout: layout, formats: [$1], file: $`) + else + body = File.read("#{@source_dir}/#{guide}") + result = RailsGuides::Markdown.new( + view: view, + layout: layout, + edge: @edge, + version: @version + ).render(body) + + warn_about_broken_links(result) + end + File.open(output_path, "w") do |f| f.write(result) end end diff --git a/guides/rails_guides/helpers.rb b/guides/rails_guides/helpers.rb index a6970fb90c..5ab1388c29 100644 --- a/guides/rails_guides/helpers.rb +++ b/guides/rails_guides/helpers.rb @@ -38,15 +38,6 @@ module RailsGuides end end - def author(name, nick, image = "credits_pic_blank.gif", &block) - image = "images/#{image}" - - result = tag(:img, src: image, class: "left pic", alt: name, width: 91, height: 91) - result << content_tag(:h3, name) - result << content_tag(:p, capture(&block)) - content_tag(:div, result, class: "clearfix", id: nick) - end - def code(&block) c = capture(&block) content_tag(:code, c) diff --git a/guides/rails_guides/kindle.rb b/guides/rails_guides/kindle.rb index 5c4f7d159c..8a0361ff4c 100644 --- a/guides/rails_guides/kindle.rb +++ b/guides/rails_guides/kindle.rb @@ -35,7 +35,7 @@ module Kindle def generate_front_matter(html_pages) frontmatter = [] html_pages.delete_if { |x| - if x =~ /(toc|welcome|credits|copyright).html/ + if /(toc|welcome|copyright).html/.match?(x) frontmatter << x unless x =~ /toc/ true end diff --git a/guides/rails_guides/markdown.rb b/guides/rails_guides/markdown.rb index 84f95eec68..61b371363e 100644 --- a/guides/rails_guides/markdown.rb +++ b/guides/rails_guides/markdown.rb @@ -69,7 +69,7 @@ module RailsGuides end def extract_raw_header_and_body - if @raw_body =~ /^\-{40,}$/ + if /^\-{40,}$/.match?(@raw_body) @raw_header, _, @raw_body = @raw_body.partition(/^\-{40,}$/).map(&:strip) end end @@ -89,7 +89,7 @@ module RailsGuides hierarchy = [] doc.children.each do |node| - if node.name =~ /^h[3-6]$/ + if /^h[3-6]$/.match?(node.name) case node.name when "h3" hierarchy = [node] diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb index 78820a7856..8095b8c898 100644 --- a/guides/rails_guides/markdown/renderer.rb +++ b/guides/rails_guides/markdown/renderer.rb @@ -35,7 +35,7 @@ HTML def paragraph(text) if text =~ %r{^NOTE:\s+Defined\s+in\s+<code>(.*?)</code>\.?$} %(<div class="note"><p>Defined in <code><a href="#{github_file_url($1)}">#{$1}</a></code>.</p></div>) - elsif text =~ /^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:]/ + elsif /^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:]/.match?(text) convert_notes(text) elsif text.include?("DO NOT READ THIS FILE ON GITHUB") elsif text =~ /^\[<sup>(\d+)\]:<\/sup> (.+)$/ @@ -110,7 +110,7 @@ HTML end def api_link(url) - if url =~ %r{http://api\.rubyonrails\.org/v\d+\.} + if %r{http://api\.rubyonrails\.org/v\d+\.}.match?(url) url elsif edge url.sub("api", "edgeapi") diff --git a/guides/source/2_2_release_notes.md b/guides/source/2_2_release_notes.md index afe0550a17..78a7c64afc 100644 --- a/guides/source/2_2_release_notes.md +++ b/guides/source/2_2_release_notes.md @@ -1,11 +1,11 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 2.2 Release Notes =============================== Rails 2.2 delivers a number of new and improved features. This list covers the major upgrades, but doesn't include every little bug fix and change. If you want to see everything, check out the [list of commits](https://github.com/rails/rails/commits/2-2-stable) in the main Rails repository on GitHub. -Along with Rails, 2.2 marks the launch of the [Ruby on Rails Guides](http://guides.rubyonrails.org/), the first results of the ongoing [Rails Guides hackfest](http://hackfest.rubyonrails.org/guide). This site will deliver high-quality documentation of the major features of Rails. +Along with Rails, 2.2 marks the launch of the [Ruby on Rails Guides](https://guides.rubyonrails.org/), the first results of the ongoing [Rails Guides hackfest](http://hackfest.rubyonrails.org/guide). This site will deliver high-quality documentation of the major features of Rails. -------------------------------------------------------------------------------- @@ -31,7 +31,7 @@ Along with thread safety, a lot of work has been done to make Rails work well wi Documentation ------------- -The internal documentation of Rails, in the form of code comments, has been improved in numerous places. In addition, the [Ruby on Rails Guides](http://guides.rubyonrails.org/) project is the definitive source for information on major Rails components. In its first official release, the Guides page includes: +The internal documentation of Rails, in the form of code comments, has been improved in numerous places. In addition, the [Ruby on Rails Guides](https://guides.rubyonrails.org/) project is the definitive source for information on major Rails components. In its first official release, the Guides page includes: * [Getting Started with Rails](getting_started.html) * [Rails Database Migrations](active_record_migrations.html) @@ -57,11 +57,10 @@ rake doc:guides This will put the guides inside `Rails.root/doc/guides` and you may start surfing straight away by opening `Rails.root/doc/guides/index.html` in your favourite browser. -* Lead Contributors: [Rails Documentation Team](credits.html) * Major contributions from [Xavier Noria](http://advogato.org/person/fxn/diary.html) and [Hongli Lai](http://izumi.plan99.net/blog/). * More information: * [Rails Guides hackfest](http://hackfest.rubyonrails.org/guide) - * [Help improve Rails documentation on Git branch](http://weblog.rubyonrails.org/2008/5/2/help-improve-rails-documentation-on-git-branch) + * [Help improve Rails documentation on Git branch](https://weblog.rubyonrails.org/2008/5/2/help-improve-rails-documentation-on-git-branch) Better integration with HTTP : Out of the box ETag support ---------------------------------------------------------- @@ -113,7 +112,7 @@ config.threadsafe! * More information : * [Thread safety for your Rails](http://m.onkey.org/2008/10/23/thread-safety-for-your-rails) - * [Thread safety project announcement](http://weblog.rubyonrails.org/2008/8/16/josh-peek-officially-joins-the-rails-core) + * [Thread safety project announcement](https://weblog.rubyonrails.org/2008/8/16/josh-peek-officially-joins-the-rails-core) * [Q/A: What Thread-safe Rails Means](http://blog.headius.com/2008/08/qa-what-thread-safe-rails-means.html) Active Record diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 634569fa2d..f85415ee42 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 2.3 Release Notes =============================== @@ -52,9 +52,9 @@ After some versions without an upgrade, Rails 2.3 offers some new features for R Documentation ------------- -The [Ruby on Rails guides](http://guides.rubyonrails.org/) project has published several additional guides for Rails 2.3. In addition, a [separate site](http://edgeguides.rubyonrails.org/) maintains updated copies of the Guides for Edge Rails. Other documentation efforts include a relaunch of the [Rails wiki](http://newwiki.rubyonrails.org/) and early planning for a Rails Book. +The [Ruby on Rails guides](https://guides.rubyonrails.org/) project has published several additional guides for Rails 2.3. In addition, a [separate site](http://edgeguides.rubyonrails.org/) maintains updated copies of the Guides for Edge Rails. Other documentation efforts include a relaunch of the [Rails wiki](http://newwiki.rubyonrails.org/) and early planning for a Rails Book. -* More Information: [Rails Documentation Projects](http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects) +* More Information: [Rails Documentation Projects](https://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects) Ruby 1.9.1 Support ------------------ @@ -89,7 +89,7 @@ accepts_nested_attributes_for :author, ``` * Lead Contributor: [Eloy Duran](http://superalloy.nl/) -* More Information: [Nested Model Forms](http://weblog.rubyonrails.org/2009/1/26/nested-model-forms) +* More Information: [Nested Model Forms](https://weblog.rubyonrails.org/2009/1/26/nested-model-forms) ### Nested Transactions @@ -376,7 +376,7 @@ You can write this view in Rails 2.3: * Lead Contributor: [Eloy Duran](http://superalloy.nl/) * More Information: - * [Nested Model Forms](http://weblog.rubyonrails.org/2009/1/26/nested-model-forms) + * [Nested Model Forms](https://weblog.rubyonrails.org/2009/1/26/nested-model-forms) * [complex-form-examples](https://github.com/alloy/complex-form-examples) * [What's New in Edge Rails: Nested Object Forms](http://archives.ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes) @@ -552,7 +552,7 @@ In addition to the Rack changes covered above, Railties (the core code of Rails Rails Metal is a new mechanism that provides superfast endpoints inside of your Rails applications. Metal classes bypass routing and Action Controller to give you raw speed (at the cost of all the things in Action Controller, of course). This builds on all of the recent foundation work to make Rails a Rack application with an exposed middleware stack. Metal endpoints can be loaded from your application or from plugins. * More Information: - * [Introducing Rails Metal](http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal) + * [Introducing Rails Metal](https://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal) * [Rails Metal: a micro-framework with the power of Rails](http://soylentfoo.jnewland.com/articles/2008/12/16/rails-metal-a-micro-framework-with-the-power-of-rails-m) * [Metal: Super-fast Endpoints within your Rails Apps](http://www.railsinside.com/deployment/180-metal-super-fast-endpoints-within-your-rails-apps.html) * [What's New in Edge Rails: Rails Metal](http://archives.ryandaigle.com/articles/2008/12/18/what-s-new-in-edge-rails-rails-metal) @@ -576,7 +576,7 @@ Building on thoughtbot's [Quiet Backtrace](https://github.com/thoughtbot/quietba ### Faster Boot Time in Development Mode with Lazy Loading/Autoload -Quite a bit of work was done to make sure that bits of Rails (and its dependencies) are only brought into memory when they're actually needed. The core frameworks - Active Support, Active Record, Action Controller, Action Mailer and Action View - are now using `autoload` to lazy-load their individual classes. This work should help keep the memory footprint down and improve overall Rails performance. +Quite a bit of work was done to make sure that bits of Rails (and its dependencies) are only brought into memory when they're actually needed. The core frameworks - Active Support, Active Record, Action Controller, Action Mailer, and Action View - are now using `autoload` to lazy-load their individual classes. This work should help keep the memory footprint down and improve overall Rails performance. You can also specify (by using the new `preload_frameworks` option) whether the core libraries should be autoloaded at startup. This defaults to `false` so that Rails autoloads itself piece-by-piece, but there are some circumstances where you still need to bring in everything at once - Passenger and JRuby both want to see all of Rails loaded together. diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 7ffa7d4a5c..9d15dfb2aa 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 3.0 Release Notes =============================== @@ -153,9 +153,9 @@ More information: - [New Action Mailer API in Rails 3](http://lindsaar.net/2010/ Documentation ------------- -The documentation in the Rails tree is being updated with all the API changes, additionally, the [Rails Edge Guides](http://edgeguides.rubyonrails.org/) are being updated one by one to reflect the changes in Rails 3.0. The guides at [guides.rubyonrails.org](http://guides.rubyonrails.org/) however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released). +The documentation in the Rails tree is being updated with all the API changes, additionally, the [Rails Edge Guides](http://edgeguides.rubyonrails.org/) are being updated one by one to reflect the changes in Rails 3.0. The guides at [guides.rubyonrails.org](https://guides.rubyonrails.org/) however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released). -More Information: - [Rails Documentation Projects](http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects) +More Information: - [Rails Documentation Projects](https://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects) Internationalization @@ -174,7 +174,7 @@ More Information: - [Rails 3 I18n changes](http://blog.plataformatec.com.br/2010 Railties -------- -With the decoupling of the main Rails frameworks, Railties got a huge overhaul so as to make linking up frameworks, engines or plugins as painless and extensible as possible: +With the decoupling of the main Rails frameworks, Railties got a huge overhaul so as to make linking up frameworks, engines, or plugins as painless and extensible as possible: * Each application now has its own name space, application is started with `YourAppName.boot` for example, makes interacting with other applications a lot easier. * Anything under `Rails.root/app` is now added to the load path, so you can make `app/observers/user_observer.rb` and Rails will load it without any modifications. @@ -250,7 +250,7 @@ Deprecations: More Information: * [Render Options in Rails 3](https://blog.engineyard.com/2010/render-options-in-rails-3) -* [Three reasons to love ActionController::Responder](http://weblog.rubyonrails.org/2009/8/31/three-reasons-love-responder) +* [Three reasons to love ActionController::Responder](https://weblog.rubyonrails.org/2009/8/31/three-reasons-love-responder) ### Action Dispatch @@ -422,7 +422,7 @@ More Information: Active Record ------------- -Active Record received a lot of attention in Rails 3.0, including abstraction into Active Model, a full update to the Query interface using Arel, validation updates and many enhancements and fixes. All of the Rails 2.x API will be usable through a compatibility layer that will be supported until version 3.1. +Active Record received a lot of attention in Rails 3.0, including abstraction into Active Model, a full update to the Query interface using Arel, validation updates, and many enhancements and fixes. All of the Rails 2.x API will be usable through a compatibility layer that will be supported until version 3.1. ### Query Interface diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md index 17d4ac23b6..8c3dc3454d 100644 --- a/guides/source/3_1_release_notes.md +++ b/guides/source/3_1_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 3.1 Release Notes =============================== diff --git a/guides/source/3_2_release_notes.md b/guides/source/3_2_release_notes.md index ae6eb27f35..d4c9bf357d 100644 --- a/guides/source/3_2_release_notes.md +++ b/guides/source/3_2_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 3.2 Release Notes =============================== diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index 0921cd1979..eaae695dff 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 4.0 Release Notes =============================== @@ -55,7 +55,7 @@ $ ruby /path/to/rails/railties/bin/rails new myapp --dev Major Features -------------- -[![Rails 4.0](images/rails4_features.png)](http://guides.rubyonrails.org/images/rails4_features.png) +[![Rails 4.0](images/4_0_release_notes/rails4_features.png)](https://guides.rubyonrails.org/images/4_0_release_notes/rails4_features.png) ### Upgrade diff --git a/guides/source/4_1_release_notes.md b/guides/source/4_1_release_notes.md index 2c5e665e33..0c7bd01cac 100644 --- a/guides/source/4_1_release_notes.md +++ b/guides/source/4_1_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 4.1 Release Notes =============================== diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md index 7105df5634..f7c40d19e9 100644 --- a/guides/source/4_2_release_notes.md +++ b/guides/source/4_2_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 4.2 Release Notes =============================== @@ -446,7 +446,7 @@ Please refer to the [Changelog][action-pack] for detailed changes. moved to the `responders` gem (version 2.0). Add `gem 'responders', '~> 2.0'` to your `Gemfile` to continue using these features. ([Pull Request](https://github.com/rails/rails/pull/16526), - [More Details](http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#responders)) + [More Details](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#responders)) * Removed deprecated `AbstractController::Helpers::ClassMethods::MissingHelperError` in favor of `AbstractController::Helpers::MissingHelperError`. @@ -545,7 +545,7 @@ Please refer to the [Changelog][action-pack] for detailed changes. served if the client supports it and a pre-generated gzip file (`.gz`) is on disk. By default the asset pipeline generates `.gz` files for all compressible assets. Serving gzip files minimizes data transfer and speeds up asset requests. Always - [use a CDN](http://guides.rubyonrails.org/asset_pipeline.html#cdns) if you are + [use a CDN](https://guides.rubyonrails.org/asset_pipeline.html#cdns) if you are serving assets from your Rails server in production. ([Pull Request](https://github.com/rails/rails/pull/16466)) diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md index 656838c6b8..e57ef03518 100644 --- a/guides/source/5_0_release_notes.md +++ b/guides/source/5_0_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 5.0 Release Notes =============================== @@ -73,7 +73,7 @@ This will do three main things: `ActionController::Base`. As with middleware, this will leave out any Action Controller modules that provide functionalities primarily used by browser applications. -- Configure the generators to skip generating views, helpers and assets when +- Configure the generators to skip generating views, helpers, and assets when you generate a new resource. The application provides a base for APIs, @@ -997,7 +997,7 @@ Please refer to the [Changelog][active-support] for detailed changes. * New config option `config.active_support.halt_callback_chains_on_return_false` to specify - whether ActiveRecord, ActiveModel and ActiveModel::Validations callback + whether ActiveRecord, ActiveModel, and ActiveModel::Validations callback chains can be halted by returning `false` in a 'before' callback. ([Pull Request](https://github.com/rails/rails/pull/17227)) diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md index 852d04b1f6..d26d3d3b95 100644 --- a/guides/source/5_1_release_notes.md +++ b/guides/source/5_1_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 5.1 Release Notes =============================== @@ -102,7 +102,7 @@ Secrets will be decrypted in production, using a key stored either in the [Pull Request](https://github.com/rails/rails/pull/27825) Allows specifying common parameters used for all methods in a mailer class in -order to share instance variables, headers and other common setup. +order to share instance variables, headers, and other common setup. ``` ruby class InvitationsMailer < ApplicationMailer @@ -170,7 +170,7 @@ Before Rails 5.1, there were two interfaces for handling HTML forms: `form_for` for model instances and `form_tag` for custom URLs. Rails 5.1 combines both of these interfaces with `form_with`, and -can generate form tags based on URLs, scopes or models. +can generate form tags based on URLs, scopes, or models. Using just a URL: diff --git a/guides/source/5_2_release_notes.md b/guides/source/5_2_release_notes.md index 3c36ba5f7a..c5b914fffc 100644 --- a/guides/source/5_2_release_notes.md +++ b/guides/source/5_2_release_notes.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails 5.2 Release Notes =============================== @@ -75,6 +75,9 @@ secrets introduced in Rails 5.1. Furthermore, Rails 5.2 [opens API underlying Credentials](https://github.com/rails/rails/pull/30940), so you can easily deal with other encrypted configurations, keys, and files. +You can read more about this in the +[Securing Rails Applications](security.html#custom-credentials) +guide. ### Content Security Policy @@ -85,69 +88,9 @@ Rails 5.2 ships with a new DSL that allows you to configure a for your application. You can configure a global default policy and then override it on a per-resource basis and even use lambdas to inject per-request values into the header such as account subdomains in a multi-tenant application. - -Example global policy: - -```ruby -# config/initializers/content_security_policy.rb -Rails.application.config.content_security_policy do |policy| - policy.default_src :self, :https - policy.font_src :self, :https, :data - policy.img_src :self, :https, :data - policy.object_src :none - policy.script_src :self, :https - policy.style_src :self, :https - - # Specify URI for violation reports - policy.report_uri "/csp-violation-report-endpoint" -end -``` - -Example controller overrides: - -```ruby -# Override policy inline -class PostsController < ApplicationController - content_security_policy do |p| - p.upgrade_insecure_requests true - end -end - -# Using literal values -class PostsController < ApplicationController - content_security_policy do |p| - p.base_uri "https://www.example.com" - end -end - -# Using mixed static and dynamic values -class PostsController < ApplicationController - content_security_policy do |p| - p.base_uri :self, -> { "https://#{current_user.domain}.example.com" } - end -end - -# Disabling the global CSP -class LegacyPagesController < ApplicationController - content_security_policy false, only: :index -end -``` - -To report only content violations for migrating -legacy content using the `content_security_policy_report_only` -configuration attribute: - -```ruby -# config/initializers/content_security_policy.rb -Rails.application.config.content_security_policy_report_only = true -``` - -```ruby -# Controller override -class PostsController < ApplicationController - content_security_policy_report_only only: :index -end -``` +You can read more about this in the +[Securing Rails Applications](security.html#content-security-policy) +guide. Railties -------- @@ -172,26 +115,16 @@ Please refer to the [Changelog][railties] for detailed changes. ### Notable changes -* Namespace error pages' CSS selectors to stop the styles from bleeding - into other pages when using Turbolinks. - ([Pull Request](https://github.com/rails/rails/pull/28814)) - * Added a shared section to `config/database.yml` that will be loaded for all environments. ([Pull Request](https://github.com/rails/rails/pull/28896)) -* Allow irb options to be passed from `rails console` command. - ([Pull Request](https://github.com/rails/rails/pull/29010)) - * Add `railtie.rb` to the plugin generator. ([Pull Request](https://github.com/rails/rails/pull/29576)) * Clear screenshot files in `tmp:clear` task. ([Pull Request](https://github.com/rails/rails/pull/29534)) -* Load environment file in `dbconsole` command. - ([Pull Request](https://github.com/rails/rails/pull/29725)) - * Skip unused components when running `bin/rails app:update`. If the initial app generation skipped Action Cable, Active Record etc., the update task honors those skips too. @@ -246,19 +179,11 @@ Please refer to the [Changelog][railties] for detailed changes. * Add `mini_magick` to default `Gemfile` as comment. ([Pull Request](https://github.com/rails/rails/pull/30633)) -* Gemfile for new apps: upgrade redis-rb from ~> 3.0 to 4.0. - ([Pull Request](https://github.com/rails/rails/pull/30748)) - * `rails new` and `rails plugin new` get `Active Storage` by default. Add ability to skip `Active Storage` with `--skip-active-storage` and do so automatically when `--skip-active-record` is used. ([Pull Request](https://github.com/rails/rails/pull/30101)) -* Fix minitest rails plugin. - The custom reporters are added only if needed. - This will fix conflicts with others plugins. - ([Commit](https://github.com/rails/rails/commit/ac99916fcf7bf27bb1519d4f7387c6b4c5f0463d)) - Action Cable ------------ @@ -277,9 +202,6 @@ Please refer to the [Changelog][action-cable] for detailed changes. * Hash long stream identifiers when using PostgreSQL adapter. ([Pull Request](https://github.com/rails/rails/pull/29297)) -* Add support for compatibility with redis-rb gem for 4.0 version. - ([Pull Request](https://github.com/rails/rails/pull/30748)) - Action Pack ----------- @@ -298,10 +220,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. ### Notable changes -* Add `action_controller_api` and `action_controller_base` load hooks to be - called in `ActiveSupport.on_load`. - ([Pull Request](https://github.com/rails/rails/pull/28402)) - * Add support for recyclable cache keys with fragment caching. ([Pull Request](https://github.com/rails/rails/pull/29092)) @@ -312,18 +230,9 @@ Please refer to the [Changelog][action-pack] for detailed changes. * AEAD encrypted cookies and sessions with GCM. ([Pull Request](https://github.com/rails/rails/pull/28132)) -* `driven_by` now registers poltergeist and capybara-webkit. - ([Pull Request](https://github.com/rails/rails/pull/29315)) - -* Fallback `ActionController::Parameters#to_s` to `Hash#to_s`. - ([Pull Request](https://github.com/rails/rails/pull/29630)) - * Protect from forgery by default. ([Pull Request](https://github.com/rails/rails/pull/29742)) -* Make `take_failed_screenshot` work within engine. - ([Pull Request](https://github.com/rails/rails/pull/30421)) - * Enforce signed/encrypted cookie expiry server side. ([Pull Request](https://github.com/rails/rails/pull/30121)) @@ -353,9 +262,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. [Commit](https://github.com/rails/rails/commit/619b1b6353a65e1635d10b8f8c6630723a5a6f1a), [Commit](https://github.com/rails/rails/commit/4ec8bf68ff92f35e79232fbd605012ce1f4e1e6e)) -* Fix optimized url helpers when using relative url root. - ([Pull Request](https://github.com/rails/rails/pull/31261)) - * Register most popular audio/video/font mime types supported by modern browsers. ([Pull Request](https://github.com/rails/rails/pull/31251)) @@ -409,21 +315,10 @@ Please refer to the [Changelog][action-view] for detailed changes. ### Notable changes -* Update `distance_of_time_in_words` helper to display better error messages - for bad input. - ([Pull Request](https://github.com/rails/rails/pull/20701)) - * Add `:json` type to `auto_discovery_link_tag` to support [JSON Feeds](https://jsonfeed.org/version/1). ([Pull Request](https://github.com/rails/rails/pull/29158)) -* Generate field ids in `collection_check_boxes` and - `collection_radio_buttons`. - ([Pull Request](https://github.com/rails/rails/pull/29412)) - -* Fix issues with scopes and engine on `current_page?` method. - ([Pull Request](https://github.com/rails/rails/pull/29503)) - * Add `srcset` option to `image_tag` helper. ([Pull Request](https://github.com/rails/rails/pull/29349)) @@ -453,10 +348,6 @@ Please refer to the [Changelog][action-mailer] for detailed changes. * Add `assert_enqueued_email_with` test helper. ([Pull Request](https://github.com/rails/rails/pull/30695)) -* Bring back proc with arity of 1 in `ActionMailer::Base.default` proc - since it was supported in Rails 5.0 but not deprecated. - ([Pull Request](https://github.com/rails/rails/pull/30391)) - Active Record ------------- @@ -546,9 +437,6 @@ Please refer to the [Changelog][active-record] for detailed changes. when the current migration does not exist. ([Commit](https://github.com/rails/rails/commit/bb9d6eb094f29bb94ef1f26aa44f145f17b973fe)) -* Add type caster to `RuntimeReflection#alias_name`. - ([Pull Request](https://github.com/rails/rails/pull/28961)) - * Respect `SchemaDumper.ignore_tables` in rake tasks for databases structure dump. ([Pull Request](https://github.com/rails/rails/pull/29077)) @@ -559,39 +447,16 @@ Please refer to the [Changelog][active-record] for detailed changes. does not include a timestamp any more. ([Pull Request](https://github.com/rails/rails/pull/29092)) -* Loading model schema from database is now thread-safe. - ([Pull Request](https://github.com/rails/rails/pull/29216)) - * Prevent creation of bind param if casted value is nil. ([Pull Request](https://github.com/rails/rails/pull/29282)) * Use bulk INSERT to insert fixtures for better performance. ([Pull Request](https://github.com/rails/rails/pull/29504)) -* Fix destroying existing object does not work well when optimistic locking - enabled and `locking_column` is null in the database. - ([Pull Request](https://github.com/rails/rails/pull/28926)) - -* `ActiveRecord::Persistence#touch` does not work well - when optimistic locking enabled and `locking_column`, - without default value, is null in the database. - ([Pull Request](https://github.com/rails/rails/pull/28914)) - * Merging two relations representing nested joins no longer transforms the joins of the merged relation into LEFT OUTER JOIN. ([Pull Request](https://github.com/rails/rails/pull/27063)) -* Previously, when building records using a `has_many :through` association, - if the child records were deleted before the parent was saved, - they would still be persisted. Now, if child records are deleted - before the parent is saved on a `has_many :through` association, - the child records will not be persisted. - ([Pull Request](https://github.com/rails/rails/pull/29593)) - -* Query cache was unavailable when entering the `ActiveRecord::Base.cache` - block without being connected. - ([Pull Request](https://github.com/rails/rails/pull/29609)) - * Fix transactions to apply state to child transactions. Previously, if you had a nested transaction and the outer transaction was rolledback, the record from the inner transaction would still be marked @@ -617,26 +482,10 @@ Please refer to the [Changelog][active-record] for detailed changes. recognize 't' and 'f' as was previously serialized. ([Pull Request](https://github.com/rails/rails/pull/29699)) -* `Relation#joins` is no longer affected by the target model's - `current_scope`, with the exception of `unscoped`. - ([Commit](https://github.com/rails/rails/commit/5c71000d086cc42516934415b79380c2224e1614)) - * Values constructed using multi-parameter assignment will now use the post-type-cast value for rendering in single-field form inputs. ([Commit](https://github.com/rails/rails/commit/1519e976b224871c7f7dd476351930d5d0d7faf6)) -* Fix `unscoped(where: [columns])` removing the wrong bind values. - ([Pull Request](https://github.com/rails/rails/pull/29780)) - -* When a `has_one` association is destroyed by `dependent: destroy`, - `destroyed_by_association` will now be set to the reflection, matching the - behaviour of `has_many` associations. - ([Pull Request](https://github.com/rails/rails/pull/29855)) - -* Fix `COUNT(DISTINCT ...)` with `ORDER BY` and `LIMIT` - to keep the existing select list. - ([Pull Request](https://github.com/rails/rails/pull/29848)) - * `ApplicationRecord` is no longer generated when generating models. If you need to generate it, it can be created with `rails g application_record`. ([Pull Request](https://github.com/rails/rails/pull/29916)) @@ -652,9 +501,6 @@ Please refer to the [Changelog][active-record] for detailed changes. * Add `binary` fixture helper method. ([Pull Request](https://github.com/rails/rails/pull/30073)) -* Ensure `sum` honors `distinct` on `has_many :through` associations. - ([Commit](https://github.com/rails/rails/commit/566f1fd068711dfe557bef63406f8dd6d41d473d)) - * Automatically guess the inverse associations for STI. ([Pull Request](https://github.com/rails/rails/pull/23425)) @@ -676,19 +522,6 @@ Please refer to the [Changelog][active-record] for detailed changes. * PostgreSQL `tsrange` now preserves subsecond precision. ([Pull Request](https://github.com/rails/rails/pull/30725)) -* Fix `COUNT(DISTINCT ...)` for `GROUP BY` with `ORDER BY` and `LIMIT`. - ([Commit](https://github.com/rails/rails/commit/5668dc6b1863ef43be8f8ef0fb1d5db913085fb3)) - -* MySQL: Don't lose `auto_increment: true` in the `db/schema.rb`. - ([Commit](https://github.com/rails/rails/commit/9493d4553569118b2a85da84fd3a8ba2b5b2de76)) - -* Fix longer sequence name detection for serial columns. - ([Pull Request](https://github.com/rails/rails/pull/28339)) - -* Fix `bin/rails db:setup` and `bin/rails db:test:prepare` create wrong - ar_internal_metadata's data for a test database. - ([Pull Request](https://github.com/rails/rails/pull/30579)) - * Raises when calling `lock!` in a dirty record. ([Commit](https://github.com/rails/rails/commit/63cf15877bae859ff7b4ebaf05186f3ca79c1863)) @@ -732,9 +565,6 @@ Please refer to the [Changelog][active-record] for detailed changes. * Add support for PostgreSQL operator classes to `add_index`. ([Pull Request](https://github.com/rails/rails/pull/19090)) -* Fix conflicts `counter_cache` with `touch: true` by optimistic locking. - ([Pull Request](https://github.com/rails/rails/pull/31405)) - * Log database query callers. ([Pull Request](https://github.com/rails/rails/pull/26815), [Pull Request](https://github.com/rails/rails/pull/31519), @@ -746,16 +576,6 @@ Please refer to the [Changelog][active-record] for detailed changes. * Using subselect for `delete_all` with `limit` or `offset`. ([Commit](https://github.com/rails/rails/commit/9e7260da1bdc0770cf4ac547120c85ab93ff3d48)) -* Fix `count(:all)` to correctly work `distinct` with custom SELECT list. - ([Commit](https://github.com/rails/rails/commit/c6cd9a59f200863ccfe8ad1d9c5a8876c39b9c5c)) - -* Fix to invoke callbacks when using `update_attribute`. - ([Commit](https://github.com/rails/rails/commit/732aa34b6e6459ad66a3d3ad107cfff75cc45160)) - -* Use `count(:all)` in `HasManyAssociation#count_records` to prevent invalid - SQL queries for association counting. - ([Pull Request](https://github.com/rails/rails/pull/27561)) - * Fixed inconsistency with `first(n)` when used with `limit()`. The `first(n)` finder now respects the `limit()`, making it consistent with `relation.to_a.first(n)`, and also with the behavior of `last(n)`. @@ -779,17 +599,10 @@ Please refer to the [Changelog][active-record] for detailed changes. * Clear the transaction state when an Active Record object is duped. ([Pull Request](https://github.com/rails/rails/pull/31751)) -* Fix `count(:all)` with eager loading and having an order other than - the driving table. - ([Commit](https://github.com/rails/rails/commit/ebc09ed9ad9a04338138739226a1a92c7a2707ee)) - * Fix not expanded problem when passing an Array object as argument to the where method using `composed_of` column. ([Pull Request](https://github.com/rails/rails/pull/31724)) -* PostgreSQL: Allow pg-1.0 gem to be used with Active Record. - ([Pull Request](https://github.com/rails/rails/pull/31671)) - * Make `reflection.klass` raise if `polymorphic?` not to be misused. ([Commit](https://github.com/rails/rails/commit/63fc1100ce054e3e11c04a547cdb9387cd79571a)) @@ -798,10 +611,6 @@ Please refer to the [Changelog][active-record] for detailed changes. even if `ORDER BY` columns include other table's primary key. ([Commit](https://github.com/rails/rails/commit/851618c15750979a75635530200665b543561a44)) -* Fix that after commit callbacks on update does not triggered - when optimistic locking is enabled. - ([Commit](https://github.com/rails/rails/commit/7f9bd034c485c2425ae0164ff5d6374834e3aa1d)) - * Fix `dependent: :destroy` issue for has_one/belongs_to relationship where the parent class was getting deleted when the child was not. ([Commit](https://github.com/rails/rails/commit/b0fc04aa3af338d5a90608bf37248668d59fc881)) @@ -818,10 +627,6 @@ Please refer to the [Changelog][active-model] for detailed changes. Change `#values` to only return the not empty values. ([Pull Request](https://github.com/rails/rails/pull/28584)) -* Fix regression in numericality validator when comparing Decimal and Float - input values with more scale than the schema. - ([Pull Request](https://github.com/rails/rails/pull/28584)) - * Add method `#merge!` for `ActiveModel::Errors`. ([Pull Request](https://github.com/rails/rails/pull/29714)) @@ -832,9 +637,6 @@ Please refer to the [Changelog][active-model] for detailed changes. is `false`. ([Pull Request](https://github.com/rails/rails/pull/31058)) -* Fix to working before/after validation callbacks on multiple contexts. - ([Pull Request](https://github.com/rails/rails/pull/31483)) - * Models using the attributes API with a proc default can now be marshalled. ([Commit](https://github.com/rails/rails/commit/0af36c62a5710e023402e37b019ad9982e69de4b)) @@ -883,10 +685,6 @@ Please refer to the [Changelog][active-support] for detailed changes. in Active Record and its use in Action Pack's fragment caching. ([Pull Request](https://github.com/rails/rails/pull/29092)) -* Fix implicit coercion calculations with scalars and durations. - ([Pull Request](https://github.com/rails/rails/pull/29163), - [Pull Request](https://github.com/rails/rails/pull/29971)) - * Add `ActiveSupport::CurrentAttributes` to provide a thread-isolated attributes singleton. Primary use case is keeping all the per-request attributes easily available to the whole system. @@ -923,9 +721,6 @@ Please refer to the [Changelog][active-support] for detailed changes. `ActiveSupport::MessageEncryptor`. ([Pull Request](https://github.com/rails/rails/pull/29892)) -* Fix modulo operations involving durations. - ([Commit](https://github.com/rails/rails/commit/a54e13bd2e8fb4d6aa0aebe59271699a2d62567b)) - * Update `String#camelize` to provide feedback when wrong option is passed. ([Pull Request](https://github.com/rails/rails/pull/30039)) @@ -1016,9 +811,6 @@ Please refer to the [Changelog][active-support] for detailed changes. This allows to specify multiple numeric differences in the same assertion. ([Pull Request](https://github.com/rails/rails/pull/31600)) -* Return all mappings for a timezone identifier in `country_zones`. - ([Commit](https://github.com/rails/rails/commit/cdce6a709e1cbc98fff009effc3b1b3ce4c7e8db)) - * Caching: MemCache and Redis `read_multi` and `fetch_multi` speedup. Read from the local in-memory cache before consulting the backend. ([Commit](https://github.com/rails/rails/commit/a2b97e4ffef971607a1be8fc7909f099b6840f36)) @@ -1030,9 +822,6 @@ Please refer to the [Changelog][active-job] for detailed changes. ### Notable changes -* Add support for compatibility with redis-rb gem for 4.0 version. - ([Pull Request](https://github.com/rails/rails/pull/30748)) - * Allow block to be passed to `ActiveJob::Base.discard_on` to allow custom handling of discard jobs. ([Pull Request](https://github.com/rails/rails/pull/30622)) diff --git a/guides/source/_welcome.html.erb b/guides/source/_welcome.html.erb index 6959f992aa..bf00ee08e5 100644 --- a/guides/source/_welcome.html.erb +++ b/guides/source/_welcome.html.erb @@ -6,21 +6,24 @@ </p> <p> If you are looking for the ones for the stable version, please check - <a href="http://guides.rubyonrails.org">http://guides.rubyonrails.org</a> instead. + <a href="https://guides.rubyonrails.org">https://guides.rubyonrails.org</a> instead. </p> <% else %> <p> - These are the new guides for Rails 5.1 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>. + These are the new guides for Rails 5.2 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>. These guides are designed to make you immediately productive with Rails, and to help you understand how all of the pieces fit together. </p> <% end %> <p> The guides for earlier releases: -<a href="http://guides.rubyonrails.org/v5.1/">Rails 5.1</a>, -<a href="http://guides.rubyonrails.org/v5.0/">Rails 5.0</a>, -<a href="http://guides.rubyonrails.org/v4.2/">Rails 4.2</a>, -<a href="http://guides.rubyonrails.org/v4.1/">Rails 4.1</a>, -<a href="http://guides.rubyonrails.org/v4.0/">Rails 4.0</a>, -<a href="http://guides.rubyonrails.org/v3.2/">Rails 3.2</a>, and -<a href="http://guides.rubyonrails.org/v2.3/">Rails 2.3</a>. +<a href="https://guides.rubyonrails.org/v5.2/">Rails 5.2</a>, +<a href="https://guides.rubyonrails.org/v5.1/">Rails 5.1</a>, +<a href="https://guides.rubyonrails.org/v5.0/">Rails 5.0</a>, +<a href="https://guides.rubyonrails.org/v4.2/">Rails 4.2</a>, +<a href="https://guides.rubyonrails.org/v4.1/">Rails 4.1</a>, +<a href="https://guides.rubyonrails.org/v4.0/">Rails 4.0</a>, +<a href="https://guides.rubyonrails.org/v3.2/">Rails 3.2</a>, +<a href="https://guides.rubyonrails.org/v3.1/">Rails 3.1</a>, +<a href="https://guides.rubyonrails.org/v3.0/">Rails 3.0</a>, and +<a href="https://guides.rubyonrails.org/v2.3/">Rails 2.3</a>. </p> diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md index c250db2e0c..14c859994c 100644 --- a/guides/source/action_cable_overview.md +++ b/guides/source/action_cable_overview.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Action Cable Overview ===================== diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index eadd517f07..7ce1f5c2a3 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Action Controller Overview ========================== @@ -23,7 +23,7 @@ What Does a Controller Do? Action Controller is the C in [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). After the router has determined which controller to use for a request, the controller is responsible for making sense of the request, and producing the appropriate output. Luckily, Action Controller does most of the groundwork for you and uses smart conventions to make this as straightforward as possible. -For most conventional [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model and use a view to create HTML output. If your controller needs to do things a little differently, that's not a problem, this is just the most common way for a controller to work. +For most conventional [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model, and use a view to create HTML output. If your controller needs to do things a little differently, that's not a problem, this is just the most common way for a controller to work. A controller can thus be thought of as a middleman between models and views. It makes the model data available to the view so it can display that data to the user, and it saves or updates user data to the model. @@ -51,7 +51,7 @@ class ClientsController < ApplicationController end ``` -As an example, if a user goes to `/clients/new` in your application to add a new client, Rails will create an instance of `ClientsController` and call its `new` method. Note that the empty method from the example above would work just fine because Rails will by default render the `new.html.erb` view unless the action says otherwise. The `new` method could make available to the view a `@client` instance variable by creating a new `Client`: +As an example, if a user goes to `/clients/new` in your application to add a new client, Rails will create an instance of `ClientsController` and call its `new` method. Note that the empty method from the example above would work just fine because Rails will by default render the `new.html.erb` view unless the action says otherwise. By creating a new `Client`, the `new` method can make a `@client` instance variable accessible in the view: ```ruby def new @@ -334,26 +334,24 @@ with a `has_many` association: params.require(:book).permit(:title, chapters_attributes: [:title]) ``` -#### Outside the Scope of Strong Parameters - -The strong parameter API was designed with the most common use cases -in mind. It is not meant as a silver bullet to handle all of your -whitelisting problems. However, you can easily mix the API with your -own code to adapt to your situation. - Imagine a scenario where you have parameters representing a product name and a hash of arbitrary data associated with that product, and you want to whitelist the product name attribute and also the whole -data hash. The strong parameters API doesn't let you directly -whitelist the whole of a nested hash with any keys, but you can use -the keys of your nested hash to declare what to whitelist: +data hash: ```ruby def product_params - params.require(:product).permit(:name, data: params[:product][:data].try(:keys)) + params.require(:product).permit(:name, data: {}) end ``` +#### Outside the Scope of Strong Parameters + +The strong parameter API was designed with the most common use cases +in mind. It is not meant as a silver bullet to handle all of your +whitelisting problems. However, you can easily mix the API with your +own code to adapt to your situation. + Session ------- @@ -397,7 +395,7 @@ You can also pass a `:domain` key and specify the domain name for the cookie: Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com" ``` -Rails sets up (for the CookieStore) a secret key used for signing the session data in `config/credentials.yml.enc`. This can be changed with `bin/rails credentials:edit`. +Rails sets up (for the CookieStore) a secret key used for signing the session data in `config/credentials.yml.enc`. This can be changed with `rails credentials:edit`. ```ruby # aws: @@ -450,14 +448,16 @@ class LoginsController < ApplicationController end ``` -To remove something from the session, assign that key to be `nil`: +To remove something from the session, delete the key/value pair: ```ruby class LoginsController < ApplicationController # "Delete" a login, aka "log the user out" def destroy # Remove the user id from the session - @_current_user = session[:current_user_id] = nil + session.delete(:current_user_id) + # Clear the memoized current user + @_current_user = nil redirect_to root_url end end @@ -476,7 +476,7 @@ Let's use the act of logging out as an example. The controller can send a messag ```ruby class LoginsController < ApplicationController def destroy - session[:current_user_id] = nil + session.delete(:current_user_id) flash[:notice] = "You have successfully logged out." redirect_to root_url end @@ -775,9 +775,9 @@ Again, this is not an ideal example for this filter, because it's not run in the Request Forgery Protection -------------------------- -Cross-site request forgery is a type of attack in which a site tricks a user into making requests on another site, possibly adding, modifying or deleting data on that site without the user's knowledge or permission. +Cross-site request forgery is a type of attack in which a site tricks a user into making requests on another site, possibly adding, modifying, or deleting data on that site without the user's knowledge or permission. -The first step to avoid this is to make sure all "destructive" actions (create, update and destroy) can only be accessed with non-GET requests. If you're following RESTful conventions you're already doing this. However, a malicious site can still send a non-GET request to your site quite easily, and that's where the request forgery protection comes in. As the name says, it protects from forged requests. +The first step to avoid this is to make sure all "destructive" actions (create, update, and destroy) can only be accessed with non-GET requests. If you're following RESTful conventions you're already doing this. However, a malicious site can still send a non-GET request to your site quite easily, and that's where the request forgery protection comes in. As the name says, it protects from forged requests. The way this is done is to add a non-guessable token which is only known to your server to each request. This way, if a request comes in without the proper token, it will be denied access. @@ -1181,22 +1181,6 @@ NOTE: Certain exceptions are only rescuable from the `ApplicationController` cla Force HTTPS protocol -------------------- -Sometime you might want to force a particular controller to only be accessible via an HTTPS protocol for security reasons. You can use the `force_ssl` method in your controller to enforce that: - -```ruby -class DinnerController - force_ssl -end -``` - -Just like the filter, you could also pass `:only` and `:except` to enforce the secure connection only to specific actions: - -```ruby -class DinnerController - force_ssl only: :cheeseburger - # or - force_ssl except: :cheeseburger -end -``` - -Please note that if you find yourself adding `force_ssl` to many controllers, you may want to force the whole application to use HTTPS instead. In that case, you can set the `config.force_ssl` in your environment file. +If you'd like to ensure that communication to your controller is only possible +via HTTPS, you should do so by enabling the `ActionDispatch::SSL` middleware via +`config.force_ssl` in your environment configuration. diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 9f239da90f..6c5f03ab38 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Action Mailer Basics ==================== @@ -20,9 +20,18 @@ Introduction ------------ Action Mailer allows you to send emails from your application using mailer classes -and views. Mailers work very similarly to controllers. They inherit from -`ActionMailer::Base` and live in `app/mailers`, and they have associated views -that appear in `app/views`. +and views. + +#### Mailers are similar to controllers + +They inherit from `ActionMailer::Base` and live in `app/mailers`. Mailers also work +very similarly to controllers. Some examples of similarities are enumerated below. +Mailers have: + +* Actions, and also, associated views that appear in `app/views`. +* Instance variables that are accessible in views. +* The ability to utilise layouts and partials. +* The ability to access a params hash. Sending Emails -------------- @@ -35,7 +44,7 @@ views. #### Create the Mailer ```bash -$ bin/rails generate mailer UserMailer +$ rails generate mailer UserMailer create app/mailers/user_mailer.rb create app/mailers/application_mailer.rb invoke erb @@ -60,8 +69,7 @@ end ``` As you can see, you can generate mailers just like you use other generators with -Rails. Mailers are conceptually similar to controllers, and so we get a mailer, -a directory for views, and a test. +Rails. If you didn't want to use a generator, you could create your own file inside of `app/mailers`, just make sure that it inherits from `ActionMailer::Base`: @@ -73,10 +81,9 @@ end #### Edit the Mailer -Mailers are very similar to Rails controllers. They also have methods called -"actions" and use views to structure the content. Where a controller generates -content like HTML to send back to the client, a Mailer creates a message to be -delivered via email. +Mailers have methods called "actions" and they use views to structure their content. +Where a controller generates content like HTML to send back to the client, a Mailer +creates a message to be delivered via email. `app/mailers/user_mailer.rb` contains an empty mailer: @@ -110,9 +117,6 @@ messages in this class. This can be overridden on a per-email basis. * `mail` - The actual email message, we are passing the `:to` and `:subject` headers in. -Just like controllers, any instance variables we define in the method become -available for use in the views. - #### Create a Mailer View Create a file called `welcome_email.html.erb` in `app/views/user_mailer/`. This @@ -169,8 +173,8 @@ Setting this up is painfully simple. First, let's create a simple `User` scaffold: ```bash -$ bin/rails generate scaffold user name email login -$ bin/rails db:migrate +$ rails generate scaffold user name email login +$ rails db:migrate ``` Now that we have a user model to play with, we will just edit the @@ -213,6 +217,8 @@ pending jobs on restart. If you need a persistent backend, you will need to use an Active Job adapter that has a persistent backend (Sidekiq, Resque, etc). +NOTE: When calling `deliver_later` the job will be placed under `mailers` queue. Make sure Active Job adapter support it otherwise the job may be silently ignored preventing email delivery. You can change that by specifying `config.action_mailer.deliver_later_queue_name` option. + If you want to send emails right away (from a cronjob for example) just call `deliver_now`: @@ -234,7 +240,7 @@ params. The method `welcome_email` returns an `ActionMailer::MessageDelivery` object which can then just be told `deliver_now` or `deliver_later` to send itself out. The `ActionMailer::MessageDelivery` object is just a wrapper around a `Mail::Message`. If -you want to inspect, alter or do anything else with the `Mail::Message` object you can +you want to inspect, alter, or do anything else with the `Mail::Message` object you can access it with the `message` method on the `ActionMailer::MessageDelivery` object. ### Auto encoding header values @@ -266,7 +272,7 @@ Action Mailer makes it very easy to add attachments. * Pass the file name and content and Action Mailer and the [Mail gem](https://github.com/mikel/mail) will automatically guess the - mime_type, set the encoding and create the attachment. + mime_type, set the encoding, and create the attachment. ```ruby attachments['filename.jpg'] = File.read('/path/to/filename.jpg') diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index c01d1082b6..495ae9d267 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Action View Overview ==================== @@ -29,7 +29,7 @@ For each controller there is an associated directory in the `app/views` director Let's take a look at what Rails does by default when creating a new resource using the scaffold generator: ```bash -$ bin/rails generate scaffold article +$ rails generate scaffold article [...] invoke scaffold_controller create app/controllers/articles_controller.rb @@ -48,7 +48,7 @@ For example, the index controller action of the `articles_controller.rb` will us The complete HTML returned to the client is composed of a combination of this ERB file, a layout template that wraps it, and all the partials that the view may reference. Within this guide you will find more detailed documentation about each of these three components. -Templates, Partials and Layouts +Templates, Partials, and Layouts ------------------------------- As mentioned, the final HTML output is a composition of three Rails elements: `Templates`, `Partials` and `Layouts`. @@ -62,7 +62,7 @@ Rails supports multiple template systems and uses a file extension to distinguis #### ERB -Within an ERB template, Ruby code can be included using both `<% %>` and `<%= %>` tags. The `<% %>` tags are used to execute Ruby code that does not return anything, such as conditions, loops or blocks, and the `<%= %>` tags are used when you want output. +Within an ERB template, Ruby code can be included using both `<% %>` and `<%= %>` tags. The `<% %>` tags are used to execute Ruby code that does not return anything, such as conditions, loops, or blocks, and the `<%= %>` tags are used when you want output. Consider the following loop for names: @@ -760,7 +760,7 @@ time_ago_in_words(3.minutes.from_now) # => 3 minutes #### time_select -Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified time-based attribute. The selects are prepared for multi-parameter assignment to an Active Record object. +Returns a set of select tags (one for hour, minute, and optionally second) pre-selected for accessing a specified time-based attribute. The selects are prepared for multi-parameter assignment to an Active Record object. ```ruby # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute @@ -1267,8 +1267,8 @@ password_field_tag 'pass' Creates a radio button; use groups of radio buttons named the same to allow users to select from a group of options. ```ruby -radio_button_tag 'gender', 'male' -# => <input id="gender_male" name="gender" type="radio" value="male" /> +radio_button_tag 'favorite_color', 'maroon' +# => <input id="favorite_color_maroon" name="favorite_color" type="radio" value="maroon" /> ``` #### select_tag diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index 6d52ac0a99..4dc69ef911 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Job Basics ================= @@ -50,7 +50,7 @@ Active Job provides a Rails generator to create jobs. The following will create job in `app/jobs` (with an attached test case under `test/jobs`): ```bash -$ bin/rails generate job guests_cleanup +$ rails generate job guests_cleanup invoke test_unit create test/jobs/guests_cleanup_job_test.rb create app/jobs/guests_cleanup_job.rb @@ -59,7 +59,7 @@ create app/jobs/guests_cleanup_job.rb You can also create a job that will run on a specific queue: ```bash -$ bin/rails generate job guests_cleanup --queue urgent +$ rails generate job guests_cleanup --queue urgent ``` If you don't want to use a generator, you could create your own file inside of @@ -120,7 +120,7 @@ production apps will need to pick a persistent backend. ### Backends Active Job has built-in adapters for multiple queuing backends (Sidekiq, -Resque, Delayed Job and others). To get an up-to-date list of the adapters +Resque, Delayed Job, and others). To get an up-to-date list of the adapters see the API Documentation for [ActiveJob::QueueAdapters](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html). ### Setting the Backend diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index ee0472621b..2e1bb1a23d 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Model Basics =================== @@ -61,7 +61,7 @@ person.age_highest? # => false `ActiveModel::Callbacks` gives Active Record style callbacks. This provides an ability to define callbacks which run at appropriate times. -After defining callbacks, you can wrap them with before, after and around +After defining callbacks, you can wrap them with before, after, and around custom methods. ```ruby @@ -459,17 +459,18 @@ features out of the box. `ActiveModel::SecurePassword` provides a way to securely store any password in an encrypted form. When you include this module, a `has_secure_password` class method is provided which defines -a `password` accessor with certain validations on it. +a `password` accessor with certain validations on it by default. #### Requirements `ActiveModel::SecurePassword` depends on [`bcrypt`](https://github.com/codahale/bcrypt-ruby 'BCrypt'), so include this gem in your `Gemfile` to use `ActiveModel::SecurePassword` correctly. -In order to make this work, the model must have an accessor named `password_digest`. -The `has_secure_password` will add the following validations on the `password` accessor: +In order to make this work, the model must have an accessor named `XXX_digest`. +Where `XXX` is the attribute name of your desired password. +The following validations are added automatically: 1. Password should be present. -2. Password should be equal to its confirmation (provided `password_confirmation` is passed along). +2. Password should be equal to its confirmation (provided `XXX_confirmation` is passed along). 3. The maximum length of a password is 72 (required by `bcrypt` on which ActiveModel::SecurePassword depends) #### Examples @@ -478,7 +479,9 @@ The `has_secure_password` will add the following validations on the `password` a class Person include ActiveModel::SecurePassword has_secure_password - attr_accessor :password_digest + has_secure_password :recovery_password, validations: false + + attr_accessor :password_digest, :recovery_password_digest end person = Person.new @@ -502,4 +505,17 @@ person.valid? # => true # When all validations are passed. person.password = person.password_confirmation = 'aditya' person.valid? # => true + +person.recovery_password = "42password" + +person.authenticate('aditya') # => person +person.authenticate('notright') # => false +person.authenticate_password('aditya') # => person +person.authenticate_password('notright') # => false + +person.authenticate_recovery_password('42password') # => person +person.authenticate_recovery_password('notright') # => false + +person.password_digest # => "$2a$04$gF8RfZdoXHvyTjHhiU4ZsO.kQqV9oonYZu31PRE4hLQn3xM2qkpIy" +person.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC" ``` diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index ef5ddb5282..fad4c19827 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record Basics ==================== @@ -13,7 +13,7 @@ After reading this guide, you will know: * How to use Active Record models to manipulate data stored in a relational database. * Active Record schema naming conventions. -* The concepts of database migrations, validations and callbacks. +* The concepts of database migrations, validations, and callbacks. -------------------------------------------------------------------------------- @@ -211,7 +211,7 @@ to allow an application to read and manipulate data stored within its tables. ### Create -Active Record objects can be created from a hash, a block or have their +Active Record objects can be created from a hash, a block, or have their attributes manually set after creation. The `new` method will return a new object while `create` will return the object and save it to the database. @@ -324,7 +324,7 @@ Validations Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not -already in the database, follows a specific format and many more. +already in the database, follows a specific format, and many more. Validation is a very important issue to consider when persisting to the database, so the methods `save` and `update` take it into account when @@ -353,7 +353,7 @@ Callbacks Active Record callbacks allow you to attach code to certain events in the life-cycle of your models. This enables you to add behavior to your models by transparently executing code when those events occur, like when you create a new -record, update it, destroy it and so on. You can learn more about callbacks in +record, update it, destroy it, and so on. You can learn more about callbacks in the [Active Record Callbacks guide](active_record_callbacks.html). Migrations @@ -387,5 +387,5 @@ provides rollback features. To actually create the table, you'd run `rails db:mi and to roll it back, `rails db:rollback`. Note that the above code is database-agnostic: it will run in MySQL, -PostgreSQL, Oracle and others. You can learn more about migrations in the +PostgreSQL, Oracle, and others. You can learn more about migrations in the [Active Record Migrations guide](active_record_migrations.html). diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index 4f54b4c206..5b06ff78bb 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record Callbacks ======================= @@ -184,9 +184,9 @@ class Company < ApplicationRecord after_touch :log_when_employees_or_company_touched private - def log_when_employees_or_company_touched - puts 'Employee/Company was touched' - end + def log_when_employees_or_company_touched + puts 'Employee/Company was touched' + end end >> @employee = Employee.last @@ -194,8 +194,8 @@ end # triggers @employee.company.touch >> @employee.touch -Employee/Company was touched An Employee was touched +Employee/Company was touched => true ``` @@ -408,7 +408,7 @@ end NOTE: The `:on` option specifies when a callback will be fired. If you don't supply the `:on` option the callback will fire for every action. -Since using `after_commit` callback only on create, update or delete is +Since using `after_commit` callback only on create, update, or delete is common, there are aliases for those operations: * `after_create_commit` diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index 5be514c786..cfa444fda0 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record Migrations ======================== @@ -12,7 +12,7 @@ After reading this guide, you will know: * The generators you can use to create them. * The methods Active Record provides to manipulate your database. -* The bin/rails tasks that manipulate migrations and your schema. +* The rails commands that manipulate migrations and your schema. * How migrations relate to `schema.rb`. -------------------------------------------------------------------------------- @@ -123,7 +123,7 @@ Of course, calculating timestamps is no fun, so Active Record provides a generator to handle making it for you: ```bash -$ bin/rails generate migration AddPartNumberToProducts +$ rails generate migration AddPartNumberToProducts ``` This will create an empty but appropriately named migration: @@ -140,7 +140,7 @@ followed by a list of column names and types then a migration containing the appropriate `add_column` and `remove_column` statements will be created. ```bash -$ bin/rails generate migration AddPartNumberToProducts part_number:string +$ rails generate migration AddPartNumberToProducts part_number:string ``` will generate @@ -156,7 +156,7 @@ end If you'd like to add an index on the new column, you can do that as well: ```bash -$ bin/rails generate migration AddPartNumberToProducts part_number:string:index +$ rails generate migration AddPartNumberToProducts part_number:string:index ``` will generate @@ -174,7 +174,7 @@ end Similarly, you can generate a migration to remove a column from the command line: ```bash -$ bin/rails generate migration RemovePartNumberFromProducts part_number:string +$ rails generate migration RemovePartNumberFromProducts part_number:string ``` generates @@ -190,7 +190,7 @@ end You are not limited to one magically generated column. For example: ```bash -$ bin/rails generate migration AddDetailsToProducts part_number:string price:decimal +$ rails generate migration AddDetailsToProducts part_number:string price:decimal ``` generates @@ -209,7 +209,7 @@ followed by a list of column names and types then a migration creating the table XXX with the columns listed will be generated. For example: ```bash -$ bin/rails generate migration CreateProducts name:string part_number:string +$ rails generate migration CreateProducts name:string part_number:string ``` generates @@ -233,7 +233,7 @@ Also, the generator accepts column type as `references` (also available as `belongs_to`). For instance: ```bash -$ bin/rails generate migration AddUserRefToProducts user:references +$ rails generate migration AddUserRefToProducts user:references ``` generates @@ -252,7 +252,7 @@ For more `add_reference` options, visit the [API documentation](http://api.rubyo There is also a generator which will produce join tables if `JoinTable` is part of the name: ```bash -$ bin/rails g migration CreateJoinTableCustomerProduct customer product +$ rails g migration CreateJoinTableCustomerProduct customer product ``` will produce the following migration: @@ -276,7 +276,7 @@ relevant table. If you tell Rails what columns you want, then statements for adding these columns will also be created. For example, running: ```bash -$ bin/rails generate model Product name:string description:text +$ rails generate model Product name:string description:text ``` will create a migration that looks like this @@ -304,7 +304,7 @@ the command line. They are enclosed by curly braces and follow the field type: For instance, running: ```bash -$ bin/rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{polymorphic} +$ rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{polymorphic} ``` will produce a migration that looks like this @@ -560,7 +560,7 @@ argument. Provide the original column options too, otherwise Rails can't recreate the column exactly when rolling back: ```ruby -remove_column :posts, :slug, :string, null: false, default: '', index: true +remove_column :posts, :slug, :string, null: false, default: '' ``` If you're going to need to use any other methods, you should use `reversible` @@ -727,15 +727,15 @@ you will have to use `structure.sql` as dump method. See Running Migrations ------------------ -Rails provides a set of bin/rails tasks to run certain sets of migrations. +Rails provides a set of rails commands to run certain sets of migrations. -The very first migration related bin/rails task you will use will probably be +The very first migration related rails command you will use will probably be `rails db:migrate`. In its most basic form it just runs the `change` or `up` method for all the migrations that have not yet been run. If there are no such migrations, it exits. It will run these migrations in order based on the date of the migration. -Note that running the `db:migrate` task also invokes the `db:schema:dump` task, which +Note that running the `db:migrate` command also invokes the `db:schema:dump` command, which will update your `db/schema.rb` file to match the structure of your database. If you specify a target version, Active Record will run the required migrations @@ -744,7 +744,7 @@ is the numerical prefix on the migration's filename. For example, to migrate to version 20080906120000 run: ```bash -$ bin/rails db:migrate VERSION=20080906120000 +$ rails db:migrate VERSION=20080906120000 ``` If version 20080906120000 is greater than the current version (i.e., it is @@ -761,7 +761,7 @@ mistake in it and wish to correct it. Rather than tracking down the version number associated with the previous migration you can run: ```bash -$ bin/rails db:rollback +$ rails db:rollback ``` This will rollback the latest migration, either by reverting the `change` @@ -769,31 +769,31 @@ method or by running the `down` method. If you need to undo several migrations you can provide a `STEP` parameter: ```bash -$ bin/rails db:rollback STEP=3 +$ rails db:rollback STEP=3 ``` will revert the last 3 migrations. -The `db:migrate:redo` task is a shortcut for doing a rollback and then migrating -back up again. As with the `db:rollback` task, you can use the `STEP` parameter +The `db:migrate:redo` command is a shortcut for doing a rollback and then migrating +back up again. As with the `db:rollback` command, you can use the `STEP` parameter if you need to go more than one version back, for example: ```bash -$ bin/rails db:migrate:redo STEP=3 +$ rails db:migrate:redo STEP=3 ``` -Neither of these bin/rails tasks do anything you could not do with `db:migrate`. They +Neither of these rails commands do anything you could not do with `db:migrate`. They are simply more convenient, since you do not need to explicitly specify the version to migrate to. ### Setup the Database -The `rails db:setup` task will create the database, load the schema and initialize +The `rails db:setup` command will create the database, load the schema, and initialize it with the seed data. ### Resetting the Database -The `rails db:reset` task will drop the database and set it up again. This is +The `rails db:reset` command will drop the database and set it up again. This is functionally equivalent to `rails db:drop db:setup`. NOTE: This is not the same as running all the migrations. It will only use the @@ -804,28 +804,28 @@ contents of the current `db/schema.rb` or `db/structure.sql` file. If a migratio ### Running Specific Migrations If you need to run a specific migration up or down, the `db:migrate:up` and -`db:migrate:down` tasks will do that. Just specify the appropriate version and +`db:migrate:down` commands will do that. Just specify the appropriate version and the corresponding migration will have its `change`, `up` or `down` method invoked, for example: ```bash -$ bin/rails db:migrate:up VERSION=20080906120000 +$ rails db:migrate:up VERSION=20080906120000 ``` will run the 20080906120000 migration by running the `change` method (or the -`up` method). This task will +`up` method). This command will first check whether the migration is already performed and will do nothing if Active Record believes that it has already been run. ### Running Migrations in Different Environments -By default running `bin/rails db:migrate` will run in the `development` environment. +By default running `rails db:migrate` will run in the `development` environment. To run migrations against another environment you can specify it using the `RAILS_ENV` environment variable while running the command. For example to run migrations against the `test` environment you could run: ```bash -$ bin/rails db:migrate RAILS_ENV=test +$ rails db:migrate RAILS_ENV=test ``` ### Changing the Output of Running Migrations @@ -896,7 +896,7 @@ Occasionally you will make a mistake when writing a migration. If you have already run the migration, then you cannot just edit the migration and run the migration again: Rails thinks it has already run the migration and so will do nothing when you run `rails db:migrate`. You must rollback the migration (for -example with `bin/rails db:rollback`), edit your migration and then run +example with `rails db:rollback`), edit your migration, and then run `rails db:migrate` to run the corrected version. In general, editing existing migrations is not a good idea. You will be @@ -917,35 +917,29 @@ Schema Dumping and You ### What are Schema Files for? Migrations, mighty as they may be, are not the authoritative source for your -database schema. That role falls to either `db/schema.rb` or an SQL file which -Active Record generates by examining the database. They are not designed to be -edited, they just represent the current state of the database. +database schema. Your database remains the authoritative source. By default, +Rails generates `db/schema.rb` which attempts to capture the current state of +your database schema. -There is no need (and it is error prone) to deploy a new instance of an app by -replaying the entire migration history. It is much simpler and faster to just -load into the database a description of the current schema. - -For example, this is how the test database is created: the current development -database is dumped (either to `db/schema.rb` or `db/structure.sql`) and then -loaded into the test database. +It tends to be faster and less error prone to create a new instance of your +application's database by loading the schema file via `rails db:schema:load` +than it is to replay the entire migration history. Old migrations may fail to +apply correctly if those migrations use changing external dependencies or rely +on application code which evolves separately from your migrations. Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations, but the information is nicely -summed up in the schema file. The -[annotate_models](https://github.com/ctran/annotate_models) gem automatically -adds and updates comments at the top of each model summarizing the schema if -you desire that functionality. +summed up in the schema file. ### Types of Schema Dumps -There are two ways to dump the schema. This is set in `config/application.rb` -by the `config.active_record.schema_format` setting, which may be either `:sql` -or `:ruby`. +The format of the schema dump generated by Rails is controlled by the +`config.active_record.schema_format` setting in `config/application.rb`. By +default, the format is `:ruby`, but can also be set to `:sql`. If `:ruby` is selected, then the schema is stored in `db/schema.rb`. If you look -at this file you'll find that it looks an awful lot like one very big -migration: +at this file you'll find that it looks an awful lot like one very big migration: ```ruby ActiveRecord::Schema.define(version: 20080906171750) do @@ -967,36 +961,32 @@ end In many ways this is exactly what it is. This file is created by inspecting the database and expressing its structure using `create_table`, `add_index`, and so -on. Because this is database-independent, it could be loaded into any database -that Active Record supports. This could be very useful if you were to -distribute an application that is able to run against multiple databases. - -NOTE: `db/schema.rb` cannot express database specific items such as triggers, -sequences, stored procedures or check constraints, etc. Please note that while -custom SQL statements can be run in migrations, these statements cannot be reconstituted -by the schema dumper. If you are using features like this, then you -should set the schema format to `:sql`. - -Instead of using Active Record's schema dumper, the database's structure will -be dumped using a tool specific to the database (via the `db:structure:dump` -rails task) into `db/structure.sql`. For example, for PostgreSQL, the `pg_dump` -utility is used. For MySQL and MariaDB, this file will contain the output of -`SHOW CREATE TABLE` for the various tables. - -Loading these schemas is simply a question of executing the SQL statements they -contain. By definition, this will create a perfect copy of the database's -structure. Using the `:sql` schema format will, however, prevent loading the -schema into a RDBMS other than the one used to create it. +on. + +`db/schema.rb` cannot express everything your database may support such as +triggers, sequences, stored procedures, check constraints, etc. While migrations +may use `execute` to create database constructs that are not supported by the +Ruby migration DSL, these constructs may not be able to be reconstituted by the +schema dumper. If you are using features like these, you should set the schema +format to `:sql` in order to get an accurate schema file that is useful to +create new database instances. + +When the schema format is set to `:sql`, the database structure will be dumped +using a tool specific to the database into `db/structure.sql`. For example, for +PostgreSQL, the `pg_dump` utility is used. For MySQL and MariaDB, this file will +contain the output of `SHOW CREATE TABLE` for the various tables. + +To load the schema from `db/structure.sql`, run `rails db:structure:load`. +Loading this file is done by executing the SQL statements it contains. By +definition, this will create a perfect copy of the database's structure. ### Schema Dumps and Source Control -Because schema dumps are the authoritative source for your database schema, it -is strongly recommended that you check them into source control. +Because schema files are commonly used to create new databases, it is strongly +recommended that you check your schema file into source control. -`db/schema.rb` contains the current version number of the database. This -ensures conflicts are going to happen in the case of a merge where both -branches touched the schema. When that happens, solve conflicts manually, -keeping the highest version number of the two. +Merge conflicts can occur in your schema file when two branches modify schema. +To resolve these conflicts run `rails db:migrate` to regenerate the schema file. Active Record and Referential Integrity --------------------------------------- diff --git a/guides/source/active_record_postgresql.md b/guides/source/active_record_postgresql.md index 6c6c6a1ded..16c1567c69 100644 --- a/guides/source/active_record_postgresql.md +++ b/guides/source/active_record_postgresql.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record and PostgreSQL ============================ @@ -276,7 +276,7 @@ end NOTE: ENUM values can't be dropped currently. You can read why [here](https://www.postgresql.org/message-id/29F36C7C98AB09499B1A209D48EAA615B7653DBC8A@mail2a.alliedtesting.com). -Hint: to show all the values of the all enums you have, you should call this query in `bin/rails db` or `psql` console: +Hint: to show all the values of the all enums you have, you should call this query in `rails db` or `psql` console: ```sql SELECT n.nspname AS enum_schema, @@ -349,7 +349,7 @@ create_table :users, force: true do |t| t.column :settings, "bit(8)" end -# app/models/device.rb +# app/models/user.rb class User < ApplicationRecord end diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 4e28e31a53..a2890b9b7a 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record Query Interface ============================= @@ -368,7 +368,7 @@ end **`:start`** -By default, records are fetched in ascending order of the primary key, which must be an integer. The `:start` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint. +By default, records are fetched in ascending order of the primary key. The `:start` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint. For example, to send newsletters only to users with the primary key starting from 2000: @@ -486,7 +486,7 @@ This makes for clearer readability if you have a large number of variable condit Active Record also allows you to pass in hash conditions which can increase the readability of your conditions syntax. With hash conditions, you pass in a hash with keys of the fields you want qualified and the values of how you want to qualify them: -NOTE: Only equality, range and subset checking are possible with Hash conditions. +NOTE: Only equality, range, and subset checking are possible with Hash conditions. #### Equality Conditions @@ -1777,6 +1777,12 @@ Client.pluck(:name) # => ["David", "Jeremy", "Jose"] ``` +You are not limited to querying fields from a single table, you can query multiple tables as well. + +``` +Client.joins(:comments, :categories).pluck("clients.email, comments.title, categories.name") +``` + Furthermore, unlike `select` and other `Relation` scopes, `pluck` triggers an immediate query, and thus cannot be chained with any further scopes, although it can work with scopes already constructed earlier: diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index d076efcd54..3f13ef8d10 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record Validations ========================= @@ -87,7 +87,7 @@ end We can see how it works by looking at some `rails console` output: ```ruby -$ bin/rails console +$ rails console >> p = Person.new(name: "John Doe") => #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil> >> p.new_record? @@ -745,7 +745,7 @@ class Person < ApplicationRecord end ``` -The block receives the record, the attribute's name and the attribute's value. +The block receives the record, the attribute's name, and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you should add an error message to the model, therefore making it invalid. @@ -927,6 +927,13 @@ class Account < ApplicationRecord end ``` +As `Lambdas` are a type of `Proc`, they can also be used to write inline +conditions in a shorter way. + +```ruby +validates :password, confirmation: true, unless: -> { password.blank? } +``` + ### Grouping Conditional validations Sometimes it is useful to have multiple validations use one condition. It can @@ -1133,24 +1140,6 @@ person.errors.full_messages # => ["Name cannot contain the characters !@#%*()_-+="] ``` -An equivalent to `errors#add` is to use `<<` to append a message to the `errors.messages` array for an attribute: - -```ruby - class Person < ApplicationRecord - def a_method_used_for_validation_purposes - errors.messages[:name] << "cannot contain the characters !@#%*()_-+=" - end - end - - person = Person.create(name: "!@#") - - person.errors[:name] - # => ["cannot contain the characters !@#%*()_-+="] - - person.errors.to_a - # => ["Name cannot contain the characters !@#%*()_-+="] -``` - ### `errors.details` You can specify a validator type to the returned error details hash using the diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 831a02a9a1..6933717c2b 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Storage Overview ======================= @@ -36,10 +36,10 @@ files. ## Setup Active Storage uses two tables in your application’s database named -`active_storage_blobs` and `active_storage_attachments`. After upgrading your -application to Rails 5.2, run `rails active_storage:install` to generate a -migration that creates these tables. Use `rails db:migrate` to run the -migration. +`active_storage_blobs` and `active_storage_attachments`. After creating a new +application (or upgrading your application to Rails 5.2), run +`rails active_storage:install` to generate a migration that creates these +tables. Use `rails db:migrate` to run the migration. Declare Active Storage services in `config/storage.yml`. For each service your application uses, provide a name and the requisite configuration. The example @@ -114,6 +114,13 @@ gem "aws-sdk-s3", require: false NOTE: The core features of Active Storage require the following permissions: `s3:ListBucket`, `s3:PutObject`, `s3:GetObject`, and `s3:DeleteObject`. If you have additional upload options configured such as setting ACLs then additional permissions may be required. +NOTE: If you want to use environment variables, standard SDK configuration files, profiles, +IAM instance profiles or task roles, you can omit the `access_key_id`, `secret_access_key`, +and `region` keys in the example above. The Amazon S3 Service supports all of the +authentication options described in the [AWS SDK documentation] +(https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html). + + ### Microsoft Azure Storage Service Declare an Azure Storage service in `config/storage.yml`: @@ -153,7 +160,7 @@ google: type: "service_account" project_id: "" private_key_id: <%= Rails.application.credentials.dig(:gcs, :private_key_id) %> - private_key: <%= Rails.application.credentials.dig(:gcs, :private_key) %> + private_key: <%= Rails.application.credentials.dig(:gcs, :private_key).dump %> client_email: "" client_id: "" auth_uri: "https://accounts.google.com/o/oauth2/auth" @@ -204,6 +211,8 @@ production: NOTE: Files are served from the primary service. +NOTE: This is not compatible with the [direct uploads](#direct-uploads) feature. + Attaching Files to Records -------------------------- @@ -223,6 +232,10 @@ end You can create a user with an avatar: +```erb +<%= form.file_field :avatar %> +``` + ```ruby class SignupController < ApplicationController def create @@ -241,13 +254,13 @@ end Call `avatar.attach` to attach an avatar to an existing user: ```ruby -Current.user.avatar.attach(params[:avatar]) +user.avatar.attach(params[:avatar]) ``` Call `avatar.attached?` to determine whether a particular user has an avatar: ```ruby -Current.user.avatar.attached? +user.avatar.attached? ``` ### `has_many_attached` @@ -292,6 +305,42 @@ Call `images.attached?` to determine whether a particular message has any images @message.images.attached? ``` +### Attaching File/IO Objects + +Sometimes you need to attach a file that doesn’t arrive via an HTTP request. +For example, you may want to attach a file you generated on disk or downloaded +from a user-submitted URL. You may also want to attach a fixture file in a +model test. To do that, provide a Hash containing at least an open IO object +and a filename: + +```ruby +@message.image.attach(io: File.open('/path/to/file'), filename: 'file.pdf') +``` + +When possible, provide a content type as well. Active Storage attempts to +determine a file’s content type from its data. It falls back to the content +type you provide if it can’t do that. + +```ruby +@message.image.attach(io: File.open('/path/to/file'), filename: 'file.pdf', content_type: 'application/pdf') +``` + +You can bypass the content type inference from the data by passing in +`identify: false` along with the `content_type`. + +```ruby +@message.image.attach( + io: File.open('/path/to/file'), + filename: 'file.pdf', + content_type: 'application/pdf', + identify: false +) +``` + +If you don’t provide a content type and Active Storage can’t determine the +file’s content type automatically, it defaults to application/octet-stream. + + Removing Files -------------- @@ -327,25 +376,63 @@ helper allows you to set the disposition. rails_blob_path(user.avatar, disposition: "attachment") ``` +If you need to create a link from outside of controller/view context (Background +jobs, Cronjobs, etc.), you can access the rails_blob_path like this: + +``` +Rails.application.routes.url_helpers.rails_blob_path(user.avatar, only_path: true) +``` + +Downloading Files +----------------- + +Sometimes you need to process a blob after it’s uploaded—for example, to convert +it to a different format. Use `ActiveStorage::Blob#download` to read a blob’s +binary data into memory: + +```ruby +binary = user.avatar.download +``` + +You might want to download a blob to a file on disk so an external program (e.g. +a virus scanner or media transcoder) can operate on it. Use +`ActiveStorage::Blob#open` to download a blob to a tempfile on disk: + +```ruby +message.video.open do |file| + system '/path/to/virus/scanner', file.path + # ... +end +``` + Transforming Images ------------------- -To create variation of the image, call `variant` on the Blob. -You can pass any [MiniMagick](https://github.com/minimagick/minimagick) -supported transformation to the method. +To create a variation of the image, call `variant` on the `Blob`. You can pass +any transformation to the method supported by the processor. The default +processor is [MiniMagick](https://github.com/minimagick/minimagick), but you +can also use [Vips](http://www.rubydoc.info/gems/ruby-vips/Vips/Image). -To enable variants, add `mini_magick` to your `Gemfile`: +To enable variants, add the `image_processing` gem to your `Gemfile`: ```ruby -gem 'mini_magick' +gem 'image_processing', '~> 1.2' ``` -When the browser hits the variant URL, Active Storage will lazy transform the -original blob into the format you specified and redirect to its new service +When the browser hits the variant URL, Active Storage will lazily transform the +original blob into the specified format and redirect to its new service location. ```erb -<%= image_tag user.avatar.variant(resize: "100x100") %> +<%= image_tag user.avatar.variant(resize_to_fit: [100, 100]) %> +``` + +To switch to the Vips processor, you would add the following to +`config/application.rb`: + +```ruby +# Use Vips for processing variants. +config.active_storage.variant_processor = :vips ``` Previewing Files @@ -359,17 +446,18 @@ the box, Active Storage supports previewing videos and PDF documents. <ul> <% @message.files.each do |file| %> <li> - <%= image_tag file.preview(resize: "100x100>") %> + <%= image_tag file.preview(resize_to_limit: [100, 100]) %> </li> <% end %> </ul> ``` -WARNING: Extracting previews requires third-party applications, `ffmpeg` for -video and `mutool` for PDFs. These libraries are not provided by Rails. You must -install them yourself to use the built-in previewers. Before you install and use -third-party software, make sure you understand the licensing implications of -doing so. +WARNING: Extracting previews requires third-party applications, FFmpeg for +video and muPDF for PDFs, and on macOS also XQuartz and Poppler. +These libraries are not provided by Rails. You must install them yourself to +use the built-in previewers. Before you install and use third-party software, +make sure you understand the licensing implications of doing so. + Direct Uploads -------------- @@ -397,7 +485,7 @@ directly from the client to the cloud. 2. Annotate file inputs with the direct upload URL. - ```ruby + ```erb <%= form.file_field :attachments, multiple: true, direct_upload: true %> ``` 3. That's it! Uploads begin upon form submission. @@ -509,6 +597,92 @@ input[type=file][data-direct-upload-url][disabled] { } ``` +### Integrating with Libraries or Frameworks + +If you want to use the Direct Upload feature from a JavaScript framework, or +you want to integrate custom drag and drop solutions, you can use the +`DirectUpload` class for this purpose. Upon receiving a file from your library +of choice, instantiate a DirectUpload and call its create method. Create takes +a callback to invoke when the upload completes. + +```js +import { DirectUpload } from "activestorage" + +const input = document.querySelector('input[type=file]') + +// Bind to file drop - use the ondrop on a parent element or use a +// library like Dropzone +const onDrop = (event) => { + event.preventDefault() + const files = event.dataTransfer.files; + Array.from(files).forEach(file => uploadFile(file)) +} + +// Bind to normal file selection +input.addEventListener('change', (event) => { + Array.from(input.files).forEach(file => uploadFile(file)) + // you might clear the selected files from the input + input.value = null +}) + +const uploadFile = (file) { + // your form needs the file_field direct_upload: true, which + // provides data-direct-upload-url + const url = input.dataset.directUploadUrl + const upload = new DirectUpload(file, url) + + upload.create((error, blob) => { + if (error) { + // Handle the error + } else { + // Add an appropriately-named hidden input to the form with a + // value of blob.signed_id so that the blob ids will be + // transmitted in the normal upload flow + const hiddenField = document.createElement('input') + hiddenField.setAttribute("type", "hidden"); + hiddenField.setAttribute("value", blob.signed_id); + hiddenField.name = input.name + document.querySelector('form').appendChild(hiddenField) + } + }) +} +``` + +If you need to track the progress of the file upload, you can pass a third +parameter to the `DirectUpload` constructor. During the upload, DirectUpload +will call the object's `directUploadWillStoreFileWithXHR` method. You can then +bind your own progress handler on the XHR. + +```js +import { DirectUpload } from "activestorage" + +class Uploader { + constructor(file, url) { + this.upload = new DirectUpload(this.file, this.url, this) + } + + upload(file) { + this.upload.create((error, blob) => { + if (error) { + // Handle the error + } else { + // Add an appropriately-named hidden input to the form + // with a value of blob.signed_id + } + }) + } + + directUploadWillStoreFileWithXHR(request) { + request.upload.addEventListener("progress", + event => this.directUploadDidProgress(event)) + } + + directUploadDidProgress(event) { + // Use event.loaded and event.total to update the progress bar + } +} +``` + Discarding Files Stored During System Tests ------------------------------------------- diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 75ad343613..dfd21915b0 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Support Core Extensions ============================== @@ -779,6 +779,14 @@ delegate :size, to: :attachment, prefix: :avatar In the previous example the macro generates `avatar_size` rather than `size`. +The option `:private` changes methods scope: + +```ruby +delegate :date_of_birth, to: :profile, private: true +``` + +The delegated methods are public by default. Pass `private: true` to change that. + NOTE: Defined in `active_support/core_ext/module/delegation.rb` #### `delegate_missing_to` @@ -2031,6 +2039,21 @@ WARNING. Keys should normally be unique. If the block returns the same value for NOTE: Defined in `active_support/core_ext/enumerable.rb`. +### `index_with` + +The method `index_with` generates a hash with the elements of an enumerable as keys. The value +is either a passed default or returned in a block. + +```ruby +%i( title body created_at ).index_with { |attr_name| post.public_send(attr_name) } +# => { title: "hey", body: "what's up?", … } + +WEEKDAYS.index_with(Interval.all_day) +# => { monday: [ 0, 1440 ], … } +``` + +NOTE: Defined in `active_support/core_ext/enumerable.rb`. + ### `many?` The method `many?` is shorthand for `collection.size > 1`: @@ -2866,9 +2889,9 @@ As the example depicts, the `:db` format generates a `BETWEEN` SQL clause. That NOTE: Defined in `active_support/core_ext/range/conversions.rb`. -### `include?` +### `===`, `include?`, and `cover?` -The methods `Range#include?` and `Range#===` say whether some value falls between the ends of a given instance: +The methods `Range#===`, `Range#include?`, and `Range#cover?` say whether some value falls between the ends of a given instance: ```ruby (2..3).include?(Math::E) # => true @@ -2877,18 +2900,23 @@ The methods `Range#include?` and `Range#===` say whether some value falls betwee Active Support extends these methods so that the argument may be another range in turn. In that case we test whether the ends of the argument range belong to the receiver themselves: ```ruby +(1..10) === (3..7) # => true +(1..10) === (0..7) # => false +(1..10) === (3..11) # => false +(1...9) === (3..9) # => false + (1..10).include?(3..7) # => true (1..10).include?(0..7) # => false (1..10).include?(3..11) # => false (1...9).include?(3..9) # => false -(1..10) === (3..7) # => true -(1..10) === (0..7) # => false -(1..10) === (3..11) # => false -(1...9) === (3..9) # => false +(1..10).cover?(3..7) # => true +(1..10).cover?(0..7) # => false +(1..10).cover?(3..11) # => false +(1...9).cover?(3..9) # => false ``` -NOTE: Defined in `active_support/core_ext/range/include_range.rb`. +NOTE: Defined in `active_support/core_ext/range/compare_range.rb`. ### `overlaps?` @@ -2907,34 +2935,6 @@ Extensions to `Date` ### Calculations -NOTE: All the following methods are defined in `active_support/core_ext/date/calculations.rb`. - -```ruby -yesterday -tomorrow -beginning_of_week (at_beginning_of_week) -end_of_week (at_end_of_week) -monday -sunday -weeks_ago -prev_week (last_week) -next_week -months_ago -months_since -beginning_of_month (at_beginning_of_month) -end_of_month (at_end_of_month) -last_month -beginning_of_quarter (at_beginning_of_quarter) -end_of_quarter (at_end_of_quarter) -beginning_of_year (at_beginning_of_year) -end_of_year (at_end_of_year) -years_ago -years_since -last_year -on_weekday? -on_weekend? -``` - INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behavior around those days for brevity, but it is enough to say that they do what you would expect. That is, `Date.new(1582, 10, 4).tomorrow` returns `Date.new(1582, 10, 15)` and so on. Please check `test/core_ext/date_ext_test.rb` in the Active Support test suite for expected behavior. #### `Date.current` @@ -2943,6 +2943,8 @@ Active Support defines `Date.current` to be today in the current time zone. That When making Date comparisons using methods which honor the user time zone, make sure to use `Date.current` and not `Date.today`. There are cases where the user time zone might be in the future compared to the system time zone, which `Date.today` uses by default. This means `Date.today` may equal `Date.yesterday`. +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Named dates ##### `beginning_of_week`, `end_of_week` @@ -2962,6 +2964,8 @@ d.end_of_week(:sunday) # => Sat, 08 May 2010 `beginning_of_week` is aliased to `at_beginning_of_week` and `end_of_week` is aliased to `at_end_of_week`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `monday`, `sunday` The methods `monday` and `sunday` return the dates for the previous Monday and @@ -2979,6 +2983,8 @@ d = Date.new(2012, 9, 16) # => Sun, 16 Sep 2012 d.sunday # => Sun, 16 Sep 2012 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `prev_week`, `next_week` The method `next_week` receives a symbol with a day name in English (default is the thread local `Date.beginning_of_week`, or `config.beginning_of_week`, or `:monday`) and it returns the date corresponding to that day. @@ -3001,6 +3007,8 @@ d.prev_week(:friday) # => Fri, 30 Apr 2010 Both `next_week` and `prev_week` work as expected when `Date.beginning_of_week` or `config.beginning_of_week` are set. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `beginning_of_month`, `end_of_month` The methods `beginning_of_month` and `end_of_month` return the dates for the beginning and end of the month: @@ -3013,6 +3021,8 @@ d.end_of_month # => Mon, 31 May 2010 `beginning_of_month` is aliased to `at_beginning_of_month`, and `end_of_month` is aliased to `at_end_of_month`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `beginning_of_quarter`, `end_of_quarter` The methods `beginning_of_quarter` and `end_of_quarter` return the dates for the beginning and end of the quarter of the receiver's calendar year: @@ -3025,6 +3035,8 @@ d.end_of_quarter # => Wed, 30 Jun 2010 `beginning_of_quarter` is aliased to `at_beginning_of_quarter`, and `end_of_quarter` is aliased to `at_end_of_quarter`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `beginning_of_year`, `end_of_year` The methods `beginning_of_year` and `end_of_year` return the dates for the beginning and end of the year: @@ -3037,6 +3049,8 @@ d.end_of_year # => Fri, 31 Dec 2010 `beginning_of_year` is aliased to `at_beginning_of_year`, and `end_of_year` is aliased to `at_end_of_year`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### Other Date Computations ##### `years_ago`, `years_since` @@ -3064,6 +3078,8 @@ Date.new(2012, 2, 29).years_since(3) # => Sat, 28 Feb 2015 `last_year` is short-hand for `#years_ago(1)`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `months_ago`, `months_since` The methods `months_ago` and `months_since` work analogously for months: @@ -3082,6 +3098,8 @@ Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010 `last_month` is short-hand for `#months_ago(1)`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `weeks_ago` The method `weeks_ago` works analogously for weeks: @@ -3091,6 +3109,8 @@ Date.new(2010, 5, 24).weeks_ago(1) # => Mon, 17 May 2010 Date.new(2010, 5, 24).weeks_ago(2) # => Mon, 10 May 2010 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `advance` The most generic way to jump to other days is `advance`. This method receives a hash with keys `:years`, `:months`, `:weeks`, `:days`, and returns a date advanced as much as the present keys indicate: @@ -3119,6 +3139,8 @@ Date.new(2010, 2, 28).advance(days: 1).advance(months: 1) # => Thu, 01 Apr 2010 ``` +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Changing Components The method `change` allows you to get a new date which is the same as the receiver except for the given year, month, or day: @@ -3135,6 +3157,8 @@ Date.new(2010, 1, 31).change(month: 2) # => ArgumentError: invalid date ``` +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Durations Durations can be added to and subtracted from dates: @@ -3177,6 +3201,8 @@ date.end_of_day # => Mon Jun 07 23:59:59 +0200 2010 `beginning_of_day` is aliased to `at_beginning_of_day`, `midnight`, `at_midnight`. +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + ##### `beginning_of_hour`, `end_of_hour` The method `beginning_of_hour` returns a timestamp at the beginning of the hour (hh:00:00): @@ -3195,6 +3221,8 @@ date.end_of_hour # => Mon Jun 07 19:59:59 +0200 2010 `beginning_of_hour` is aliased to `at_beginning_of_hour`. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `beginning_of_minute`, `end_of_minute` The method `beginning_of_minute` returns a timestamp at the beginning of the minute (hh:mm:00): @@ -3215,6 +3243,8 @@ date.end_of_minute # => Mon Jun 07 19:55:59 +0200 2010 INFO: `beginning_of_hour`, `end_of_hour`, `beginning_of_minute` and `end_of_minute` are implemented for `Time` and `DateTime` but **not** `Date` as it does not make sense to request the beginning or end of an hour or minute on a `Date` instance. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `ago`, `since` The method `ago` receives a number of seconds as argument and returns a timestamp those many seconds ago from midnight: @@ -3231,6 +3261,8 @@ date = Date.current # => Fri, 11 Jun 2010 date.since(1) # => Fri, 11 Jun 2010 00:00:01 EDT -04:00 ``` +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Other Time Computations ### Conversions @@ -3242,8 +3274,6 @@ WARNING: `DateTime` is not aware of DST rules and so some of these methods have ### Calculations -NOTE: All the following methods are defined in `active_support/core_ext/date_time/calculations.rb`. - The class `DateTime` is a subclass of `Date` so by loading `active_support/core_ext/date/calculations.rb` you inherit these methods and their aliases, except that they will always return datetimes. The following methods are reimplemented so you do **not** need to load `active_support/core_ext/date/calculations.rb` for these ones: @@ -3270,6 +3300,8 @@ end_of_hour Active Support defines `DateTime.current` to be like `Time.now.to_datetime`, except that it honors the user time zone, if defined. It also defines `DateTime.yesterday` and `DateTime.tomorrow`, and the instance predicates `past?`, and `future?` relative to `DateTime.current`. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + #### Other Extensions ##### `seconds_since_midnight` @@ -3281,6 +3313,8 @@ now = DateTime.current # => Mon, 07 Jun 2010 20:26:36 +0000 now.seconds_since_midnight # => 73596 ``` +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `utc` The method `utc` gives you the same datetime in the receiver expressed in UTC. @@ -3292,6 +3326,8 @@ now.utc # => Mon, 07 Jun 2010 23:27:52 +0000 This method is also aliased as `getutc`. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `utc?` The predicate `utc?` says whether the receiver has UTC as its time zone: @@ -3302,6 +3338,8 @@ now.utc? # => false now.utc.utc? # => true ``` +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `advance` The most generic way to jump to another datetime is `advance`. This method receives a hash with keys `:years`, `:months`, `:weeks`, `:days`, `:hours`, `:minutes`, and `:seconds`, and returns a datetime advanced as much as the present keys indicate. @@ -3333,6 +3371,8 @@ d.advance(seconds: 1).advance(months: 1) WARNING: Since `DateTime` is not DST-aware you can end up in a non-existing point in time with no warning or error telling you so. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + #### Changing Components The method `change` allows you to get a new datetime which is the same as the receiver except for the given options, which may include `:year`, `:month`, `:day`, `:hour`, `:min`, `:sec`, `:offset`, `:start`: @@ -3365,6 +3405,8 @@ DateTime.current.change(month: 2, day: 30) # => ArgumentError: invalid date ``` +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + #### Durations Durations can be added to and subtracted from datetimes: @@ -3390,52 +3432,6 @@ Extensions to `Time` ### Calculations -NOTE: All the following methods are defined in `active_support/core_ext/time/calculations.rb`. - -```ruby -past? -today? -future? -yesterday -tomorrow -seconds_since_midnight -change -advance -ago -since (in) -prev_day -next_day -beginning_of_day (midnight, at_midnight, at_beginning_of_day) -end_of_day -beginning_of_hour (at_beginning_of_hour) -end_of_hour -beginning_of_week (at_beginning_of_week) -end_of_week (at_end_of_week) -monday -sunday -weeks_ago -prev_week (last_week) -next_week -months_ago -months_since -beginning_of_month (at_beginning_of_month) -end_of_month (at_end_of_month) -prev_month -next_month -last_month -beginning_of_quarter (at_beginning_of_quarter) -end_of_quarter (at_end_of_quarter) -beginning_of_year (at_beginning_of_year) -end_of_year (at_end_of_year) -years_ago -years_since -prev_year -last_year -next_year -on_weekday? -on_weekend? -``` - They are analogous. Please refer to their documentation above and take into account the following differences: * `change` accepts an additional `:usec` option. @@ -3460,6 +3456,8 @@ Active Support defines `Time.current` to be today in the current time zone. That When making Time comparisons using methods which honor the user time zone, make sure to use `Time.current` instead of `Time.now`. There are cases where the user time zone might be in the future compared to the system time zone, which `Time.now` uses by default. This means `Time.now.to_date` may equal `Date.yesterday`. +NOTE: Defined in `active_support/core_ext/time/calculations.rb`. + #### `all_day`, `all_week`, `all_month`, `all_quarter` and `all_year` The method `all_day` returns a range representing the whole day of the current time. @@ -3488,6 +3486,8 @@ now.all_year # => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_day`, `next_day` In Ruby 1.9 `prev_day` and `next_day` return the date in the last or next day: @@ -3498,6 +3498,8 @@ d.prev_day # => Fri, 07 May 2010 d.next_day # => Sun, 09 May 2010 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_month`, `next_month` In Ruby 1.9 `prev_month` and `next_month` return the date with the same day in the last or next month: @@ -3517,6 +3519,8 @@ Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000 Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_year`, `next_year` In Ruby 1.9 `prev_year` and `next_year` return a date with the same day/month in the last or next year: @@ -3535,6 +3539,8 @@ d.prev_year # => Sun, 28 Feb 1999 d.next_year # => Wed, 28 Feb 2001 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_quarter`, `next_quarter` `prev_quarter` and `next_quarter` return the date with the same day in the previous or next quarter: @@ -3556,6 +3562,8 @@ Time.local(2000, 11, 31).next_quarter # => 2001-03-01 00:00:00 +0200 `prev_quarter` is aliased to `last_quarter`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ### Time Constructors Active Support defines `Time.current` to be `Time.zone.now` if there's a user time zone defined, with fallback to `Time.now`: diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 11c4a8222a..3568c47dd8 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -1,9 +1,9 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Support Instrumentation ============================== -Active Support is a part of core Rails that provides Ruby language extensions, utilities and other things. One of the things it includes is an instrumentation API that can be used inside an application to measure certain actions that occur within Ruby code, such as that inside a Rails application or the framework itself. It is not limited to Rails, however. It can be used independently in other Ruby scripts if it is so desired. +Active Support is a part of core Rails that provides Ruby language extensions, utilities, and other things. One of the things it includes is an instrumentation API that can be used inside an application to measure certain actions that occur within Ruby code, such as that inside a Rails application or the framework itself. It is not limited to Rails, however. It can be used independently in other Ruby scripts if it is so desired. In this guide, you will learn how to use the instrumentation API inside of Active Support to measure events inside of Rails and other Ruby code. @@ -169,7 +169,7 @@ INFO. Additional keys may be added by the caller. ### send_data.action_controller -`ActionController` does not had any specific information to the payload. All options are passed through to the payload. +`ActionController` does not add any specific information to the payload. All options are passed through to the payload. ### redirect_to.action_controller diff --git a/guides/source/api_app.md b/guides/source/api_app.md index b4d90d31de..85367c50e7 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Using Rails for API-only Applications ===================================== @@ -24,7 +24,7 @@ With the advent of client-side frameworks, more developers are using Rails to build a back-end that is shared between their web application and other native applications. -For example, Twitter uses its [public API](https://dev.twitter.com) in its web +For example, Twitter uses its [public API](https://developer.twitter.com/) in its web application, which is built as a static site that consumes JSON resources. Instead of using Rails to generate HTML that communicates with the server @@ -98,7 +98,7 @@ Handled at the Action Pack layer: - Header and Redirection Responses: `head :no_content` and `redirect_to user_url(current_user)` come in handy. Sure, you could manually add the response headers, but why? -- Caching: Rails provides page, action and fragment caching. Fragment caching +- Caching: Rails provides page, action, and fragment caching. Fragment caching is especially helpful when building up a nested JSON object. - Basic, Digest, and Token Authentication: Rails comes with out-of-the-box support for three kinds of HTTP authentication. @@ -106,7 +106,7 @@ Handled at the Action Pack layer: handlers for a variety of events, such as action processing, sending a file or data, redirection, and database queries. The payload of each event comes with relevant information (for the action processing event, the payload includes - the controller, action, parameters, request format, request method and the + the controller, action, parameters, request format, request method, and the request's full path). - Generators: It is often handy to generate a resource and get your model, controller, test stubs, and routes created for you in a single command for @@ -148,7 +148,7 @@ This will do three main things for you: `ActionController::Base`. As with middleware, this will leave out any Action Controller modules that provide functionalities primarily used by browser applications. -- Configure the generators to skip generating views, helpers and assets when +- Configure the generators to skip generating views, helpers, and assets when you generate a new resource. ### Changing an existing application @@ -375,7 +375,6 @@ controller modules by default: - `ActionController::ConditionalGet`: Support for `stale?`. - `ActionController::BasicImplicitRender`: Makes sure to return an empty response, if there isn't an explicit one. - `ActionController::StrongParameters`: Support for parameters white-listing in combination with Active Model mass assignment. -- `ActionController::ForceSSL`: Support for `force_ssl`. - `ActionController::DataStreaming`: Support for `send_file` and `send_data`. - `AbstractController::Callbacks`: Support for `before_action` and similar helpers. @@ -392,7 +391,7 @@ Other plugins may add additional modules. You can get a list of all modules included into `ActionController::API` in the rails console: ```bash -$ bin/rails c +$ rails c >> ActionController::API.ancestors - ActionController::Metal.ancestors => [ActionController::API, ActiveRecord::Railties::ControllerRuntime, @@ -413,7 +412,7 @@ Some common modules you might want to add: - `AbstractController::Translation`: Support for the `l` and `t` localization and translation methods. -- Support for basic, digest or token HTTP authentication: +- Support for basic, digest, or token HTTP authentication: * `ActionController::HttpAuthentication::Basic::ControllerMethods`, * `ActionController::HttpAuthentication::Digest::ControllerMethods`, * `ActionController::HttpAuthentication::Token::ControllerMethods` diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 10b89433e7..6efd9296dc 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** API Documentation Guidelines ============================ diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 2f5854fed0..bf046a3341 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** The Asset Pipeline ================== @@ -20,7 +20,7 @@ What is the Asset Pipeline? The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in -other languages and pre-processors such as CoffeeScript, Sass and ERB. +other languages and pre-processors such as CoffeeScript, Sass, and ERB. It allows assets in your application to be automatically combined with assets from other gems. @@ -224,7 +224,7 @@ Pipeline assets can be placed inside an application in one of three locations: `app/assets`, `lib/assets` or `vendor/assets`. * `app/assets` is for assets that are owned by the application, such as custom -images, JavaScript files or stylesheets. +images, JavaScript files, or stylesheets. * `lib/assets` is for your own libraries' code that doesn't really fit into the scope of the application or those libraries which are shared across applications. @@ -434,7 +434,7 @@ Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ - instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if -necessary, concatenates them into one single file and then compresses them +necessary, concatenates them into one single file, and then compresses them (based on value of `Rails.application.config.assets.js_compressor`). By serving one file rather than many, the load time of pages can be greatly reduced because the browser makes fewer requests. Compression also reduces file size, enabling @@ -673,20 +673,20 @@ content changes. ### Precompiling Assets -Rails comes bundled with a task to compile the asset manifests and other +Rails comes bundled with a command to compile the asset manifests and other files in the pipeline. Compiled assets are written to the location specified in `config.assets.prefix`. By default, this is the `/assets` directory. -You can call this task on the server during deployment to create compiled +You can call this command on the server during deployment to create compiled versions of your assets directly on the server. See the next section for information on compiling locally. -The task is: +The command is: ```bash -$ RAILS_ENV=production bin/rails assets:precompile +$ RAILS_ENV=production rails assets:precompile ``` Capistrano (v2.15.1 and above) includes a recipe to handle this in deployment. @@ -698,7 +698,7 @@ load 'deploy/assets' This links the folder specified in `config.assets.prefix` to `shared/assets`. If you already use this shared folder you'll need to write your own deployment -task. +command. It is important that this folder is shared between deployments so that remotely cached pages referencing the old compiled assets still work for the life of @@ -728,8 +728,8 @@ Rails.application.config.assets.precompile += %w( admin.js admin.css ) NOTE. Always specify an expected compiled filename that ends with `.js` or `.css`, even if you want to add Sass or CoffeeScript files to the precompile array. -The task also generates a `.sprockets-manifest-md5hash.json` (where `md5hash` is -an MD5 hash) that contains a list with all your assets and their respective +The command also generates a `.sprockets-manifest-randomhex.json` (where `randomhex` is +a 16-byte random hex string) that contains a list with all your assets and their respective fingerprints. This is used by the Rails helper methods to avoid handing the mapping requests back to Sprockets. A typical manifest file looks like: @@ -845,7 +845,7 @@ signals all caches between your server and the client browser that this content number of requests for this asset from your server; the asset has a good chance of being in the local browser cache or some intermediate cache. -This mode uses more memory, performs more poorly than the default and is not +This mode uses more memory, performs more poorly than the default, and is not recommended. If you are deploying a production application to a system without any diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index f895cadea5..008c7345e9 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Active Record Associations ========================== @@ -94,9 +94,9 @@ class Book < ApplicationRecord end ``` -![belongs_to Association Diagram](images/belongs_to.png) +![belongs_to Association Diagram](images/association_basics/belongs_to.png) -NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `author` association in the `Book` model, you would be told that there was an "uninitialized constant Book::Authors". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. +NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `author` association in the `Book` model and tried to create the instance by `Book.create(authors: @author)`, you would be told that there was an "uninitialized constant Book::Authors". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. The corresponding migration might look like this: @@ -127,7 +127,7 @@ class Supplier < ApplicationRecord end ``` -![has_one Association Diagram](images/has_one.png) +![has_one Association Diagram](images/association_basics/has_one.png) The corresponding migration might look like this: @@ -171,7 +171,7 @@ end NOTE: The name of the other model is pluralized when declaring a `has_many` association. -![has_many Association Diagram](images/has_many.png) +![has_many Association Diagram](images/association_basics/has_many.png) The corresponding migration might look like this: @@ -213,7 +213,7 @@ class Patient < ApplicationRecord end ``` -![has_many :through Association Diagram](images/has_many_through.png) +![has_many :through Association Diagram](images/association_basics/has_many_through.png) The corresponding migration might look like this: @@ -299,7 +299,7 @@ class AccountHistory < ApplicationRecord end ``` -![has_one :through Association Diagram](images/has_one_through.png) +![has_one :through Association Diagram](images/association_basics/has_one_through.png) The corresponding migration might look like this: @@ -340,7 +340,7 @@ class Part < ApplicationRecord end ``` -![has_and_belongs_to_many Association Diagram](images/habtm.png) +![has_and_belongs_to_many Association Diagram](images/association_basics/habtm.png) The corresponding migration might look like this: @@ -439,7 +439,7 @@ end The simplest rule of thumb is that you should set up a `has_many :through` relationship if you need to work with the relationship model as an independent entity. If you don't need to do anything with the relationship model, it may be simpler to set up a `has_and_belongs_to_many` relationship (though you'll need to remember to create the joining table in the database). -You should use `has_many :through` if you need validations, callbacks or extra attributes on the join model. +You should use `has_many :through` if you need validations, callbacks, or extra attributes on the join model. ### Polymorphic Associations @@ -494,7 +494,7 @@ class CreatePictures < ActiveRecord::Migration[5.0] end ``` -![Polymorphic Association Diagram](images/polymorphic.png) +![Polymorphic Association Diagram](images/association_basics/polymorphic.png) ### Self Joins @@ -505,7 +505,7 @@ class Employee < ApplicationRecord has_many :subordinates, class_name: "Employee", foreign_key: "manager_id" - belongs_to :manager, class_name: "Employee" + belongs_to :manager, class_name: "Employee", optional: true end ``` @@ -600,7 +600,7 @@ NOTE: If you wish to [enforce referential integrity at the database level](/acti #### Creating Join Tables for `has_and_belongs_to_many` Associations -If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical book of the class names. So a join between author and book models will give the default join table name of "authors_books" because "a" outranks "b" in lexical ordering. +If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical order of the class names. So a join between author and book models will give the default join table name of "authors_books" because "a" outranks "b" in lexical ordering. WARNING: The precedence between model names is calculated using the `<=>` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", but it in fact generates a join table name of "paper_boxes_papers" (because the underscore '\_' is lexicographically _less_ than 's' in common encodings). @@ -2391,7 +2391,7 @@ Single Table Inheritance ------------------------ Sometimes, you may want to share fields and behavior between different models. -Let's say we have Car, Motorcycle and Bicycle models. We will want to share +Let's say we have Car, Motorcycle, and Bicycle models. We will want to share the `color` and `price` fields and some methods for all of them, but having some specific behavior for each, and separated controllers too. diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md index 5428b16edc..6298651e4a 100644 --- a/guides/source/autoloading_and_reloading_constants.md +++ b/guides/source/autoloading_and_reloading_constants.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Autoloading and Reloading Constants =================================== @@ -230,10 +230,12 @@ is not entirely equivalent to the one of the body of the definitions using the `class` and `module` keywords. But both idioms result in the same constant assignment. -Thus, when one informally says "the `String` class", that really means: the -class object stored in the constant called "String" in the class object stored -in the `Object` constant. `String` is otherwise an ordinary Ruby constant and -everything related to constants such as resolution algorithms applies to it. +Thus, an informal expression like "the `String` class" technically means the +class object stored in the constant called "String". That constant, in turn, +belongs to the class object stored in the constant called "Object". + +`String` is an ordinary constant, and everything related to them such as +resolution algorithms applies to it. Likewise, in the controller @@ -408,7 +410,7 @@ Rails is always able to autoload provided its environment is in place. For example the `runner` command autoloads: ``` -$ bin/rails runner 'p User.column_names' +$ rails runner 'p User.column_names' ["id", "email", "created_at", "updated_at"] ``` @@ -468,10 +470,10 @@ default it contains: `eager_load_paths` is initially the `app` paths above How files are autoloaded depends on `eager_load` and `cache_classes` config settings which typically vary in development, production, and test modes: - + * In **development**, you want quicker startup with incremental loading of application code. So `eager_load` should be set to `false`, and Rails will autoload files as needed (see [Autoloading Algorithms](#autoloading-algorithms) below) -- and then reload them when they change (see [Constant Reloading](#constant-reloading) below). - * In **production**, however you want consistency and thread-safety and can live with a longer boot time. So `eager_load` is set to `true`, and then during boot (before the app is ready to receive requests) Rails loads all files in the `eager_load_paths` and then turns off auto loading (NB: autoloading may be needed during eager loading). Not autoloading after boot is a `good thing`, as autoloading can cause the app to be have thread-safety problems. - * In **test**, for speed of execution (of individual tests) `eager_load` is `false`, so Rails follows development behaviour. + * In **production**, however, you want consistency and thread-safety and can live with a longer boot time. So `eager_load` is set to `true`, and then during boot (before the app is ready to receive requests) Rails loads all files in the `eager_load_paths` and then turns off auto loading (NB: autoloading may be needed during eager loading). Not autoloading after boot is a `good thing`, as autoloading can cause the app to be have thread-safety problems. + * In **test**, for speed of execution (of individual tests) `eager_load` is `false`, so Rails follows development behaviour. What is described above are the defaults with a newly generated Rails app. There are multiple ways this can be configured differently (see [Configuring Rails Applications](configuring.html#rails-general-configuration). ). But using `autoload_paths` on its own in the past (before Rails 5) developers might configure `autoload_paths` to add in extra locations (e.g. `lib` which used to be an autoload path list years ago, but no longer is). However this is now discouraged for most purposes, as it is likely to lead to production-only errors. It is possible to add new locations to both `config.eager_load_paths` and `config.autoload_paths` but use at your own risk. @@ -484,7 +486,7 @@ The value of `autoload_paths` can be inspected. In a just-generated application it is (edited): ``` -$ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths' +$ rails r 'puts ActiveSupport::Dependencies.autoload_paths' .../app/assets .../app/channels .../app/controllers @@ -1218,7 +1220,7 @@ been loaded but `app/models/hotel/image.rb` hasn't, Ruby does not find `Image` in `Hotel`, but it does in `Object`: ``` -$ bin/rails r 'Image; p Hotel::Image' 2>/dev/null +$ rails r 'Image; p Hotel::Image' 2>/dev/null Image # NOT Hotel::Image! ``` @@ -1336,15 +1338,15 @@ end ``` ### Autoloading in the Test Environment - -When configuring the `test` environment for autoloading you might consider multiple factors. -For example it might be worth running your tests with an identical setup to production (`config.eager_load = true`, `config.cache_classes = true`) in order to catch any problems before they hit production (this is compensation for the lack of dev-prod parity). However this will slow down the boot time for individual tests on a dev machine (and is not immediately compatible with spring see below). So one possibility is to do this on a -[CI](https://en.wikipedia.org/wiki/Continuous_integration) machine only (which should run without spring). +When configuring the `test` environment for autoloading you might consider multiple factors. + +For example it might be worth running your tests with an identical setup to production (`config.eager_load = true`, `config.cache_classes = true`) in order to catch any problems before they hit production (this is compensation for the lack of dev-prod parity). However this will slow down the boot time for individual tests on a dev machine (and is not immediately compatible with spring see below). So one possibility is to do this on a +[CI](https://en.wikipedia.org/wiki/Continuous_integration) machine only (which should run without spring). -On a development machine you can then have your tests running with whatever is fastest (ideally `config.eager_load = false`). +On a development machine you can then have your tests running with whatever is fastest (ideally `config.eager_load = false`). -With the [Spring](https://github.com/rails/spring) pre-loader (included with new Rails apps), you ideally keep `config.eager_load = false` as per development. Sometimes you may end up with a hybrid configuration (`config.eager_load = true`, `config.cache_classes = true` AND `config.enable_dependency_loading = true`), see [spring issue](https://github.com/rails/spring/issues/519#issuecomment-348324369). However it might be simpler to keep the same configuration as development, and work out whatever it is that is causing autoloading to fail (perhaps by the results of your CI test results). +With the [Spring](https://github.com/rails/spring) pre-loader (included with new Rails apps), you ideally keep `config.eager_load = false` as per development. Sometimes you may end up with a hybrid configuration (`config.eager_load = true`, `config.cache_classes = true` AND `config.enable_dependency_loading = true`), see [spring issue](https://github.com/rails/spring/issues/519#issuecomment-348324369). However it might be simpler to keep the same configuration as development, and work out whatever it is that is causing autoloading to fail (perhaps by the results of your CI test results). Occasionally you may need to explicitly eager_load by using `Rails -.application.eager_load!` in the setup of your tests -- this might occur if your [tests involve multithreading](https://stackoverflow.com/questions/25796409/in-rails-how-can-i-eager-load-all-code-before-a-specific-rspec-test). +.application.eager_load!` in the setup of your tests -- this might occur if your [tests involve multithreading](https://stackoverflow.com/questions/25796409/in-rails-how-can-i-eager-load-all-code-before-a-specific-rspec-test). diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 5dde6f34fa..8aaa71c557 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Caching with Rails: An Overview =============================== @@ -408,7 +408,7 @@ as well as development and test environments. New Rails projects are configured to use this implementation in development environment by default. NOTE: Since processes will not share cache data when using `:memory_store`, -it will not be possible to manually read, write or expire the cache via the Rails console. +it will not be possible to manually read, write, or expire the cache via the Rails console. ### ActiveSupport::Cache::FileStore @@ -446,30 +446,28 @@ config.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.c ### ActiveSupport::Cache::RedisCacheStore -The Redis cache store takes advantage of Redis support for least-recently-used -and least-frequently-used key eviction when it reaches max memory, allowing it -to behave much like a Memcached cache server. +The Redis cache store takes advantage of Redis support for automatic eviction +when it reaches max memory, allowing it to behave much like a Memcached cache server. Deployment note: Redis doesn't expire keys by default, so take care to use a dedicated Redis cache server. Don't fill up your persistent-Redis server with volatile cache data! Read the [Redis cache server setup guide](https://redis.io/topics/lru-cache) in detail. -For an all-cache Redis server, set `maxmemory-policy` to an `allkeys` policy. -Redis 4+ support least-frequently-used (`allkeys-lfu`) eviction, an excellent -default choice. Redis 3 and earlier should use `allkeys-lru` for -least-recently-used eviction. +For a cache-only Redis server, set `maxmemory-policy` to one of the variants of allkeys. +Redis 4+ supports least-frequently-used eviction (`allkeys-lfu`), an excellent +default choice. Redis 3 and earlier should use least-recently-used eviction (`allkeys-lru`). Set cache read and write timeouts relatively low. Regenerating a cached value is often faster than waiting more than a second to retrieve it. Both read and write timeouts default to 1 second, but may be set lower if your network is -consistently low latency. +consistently low-latency. By default, the cache store will not attempt to reconnect to Redis if the connection fails during a request. If you experience frequent disconnects you may wish to enable reconnect attempts. -Cache reads and writes never raise exceptions. They just return `nil` instead, +Cache reads and writes never raise exceptions; they just return `nil` instead, behaving as if there was nothing in the cache. To gauge whether your cache is hitting exceptions, you may provide an `error_handler` to report to an exception gathering service. It must accept three keyword arguments: `method`, @@ -477,12 +475,33 @@ the cache store method that was originally called; `returning`, the value that was returned to the user, typically `nil`; and `exception`, the exception that was rescued. -Putting it all together, a production Redis cache store may look something -like this: +To get started, add the redis gem to your Gemfile: ```ruby -cache_servers = %w[ "redis://cache-01:6379/0", "redis://cache-02:6379/0", … ], -config.cache_store = :redis_cache_store, url: cache_servers, +gem 'redis' +``` + +You can enable support for the faster [hiredis](https://github.com/redis/hiredis) +connection library by additionally adding its ruby wrapper to your Gemfile: + +```ruby +gem 'hiredis' +``` + +Redis cache store will automatically require & use hiredis if available. No further +configuration is needed. + +Finally, add the configuration in the relevant `config/environments/*.rb` file: + +```ruby +config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] } +``` + +A more complex, production Redis cache store may look something like this: + +```ruby +cache_servers = %w(redis://cache-01:6379/0 redis://cache-02:6379/0) +config.cache_store = :redis_cache_store, { url: cache_servers, connect_timeout: 30, # Defaults to 20 seconds read_timeout: 0.2, # Defaults to 1 second @@ -491,9 +510,10 @@ config.cache_store = :redis_cache_store, url: cache_servers, error_handler: -> (method:, returning:, exception:) { # Report errors to Sentry as warnings - Raven.capture_exception exception, level: 'warning", + Raven.capture_exception exception, level: 'warning', tags: { method: method, returning: returning } } +} ``` ### ActiveSupport::Cache::NullStore @@ -650,13 +670,13 @@ Caching in Development ---------------------- It's common to want to test the caching strategy of your application -in development mode. Rails provides the rake task `dev:cache` to +in development mode. Rails provides the rails command `dev:cache` to easily toggle caching on/off. ```bash -$ bin/rails dev:cache +$ rails dev:cache Development mode is now being cached. -$ bin/rails dev:cache +$ rails dev:cache Development mode is no longer being cached. ``` diff --git a/guides/source/command_line.md b/guides/source/command_line.md index b41e8bbec6..2f07417316 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** The Rails Command Line ====================== @@ -21,12 +21,51 @@ There are a few commands that are absolutely critical to your everyday usage of * `rails console` * `rails server` -* `bin/rails` +* `rails test` * `rails generate` +* `rails db:migrate` +* `rails db:create` +* `rails routes` * `rails dbconsole` * `rails new app_name` -All commands can run with `-h` or `--help` to list more information. +You can get a list of rails commands available to you, which will often depend on your current directory, by typing `rails --help`. Each command has a description, and should help you find the thing you need. + +```bash +$ rails --help +Usage: rails COMMAND [ARGS] + +The most common rails commands are: +generate Generate new code (short-cut alias: "g") +console Start the Rails console (short-cut alias: "c") +server Start the Rails server (short-cut alias: "s") +... + +All commands can be run with -h (or --help) for more information. + +In addition to those commands, there are: +about List versions of all Rails ... +assets:clean[keep] Remove old compiled assets +assets:clobber Remove compiled assets +assets:environment Load asset compile environment +assets:precompile Compile all the assets ... +... +db:fixtures:load Loads fixtures into the ... +db:migrate Migrate the database ... +db:migrate:status Display status of migrations +db:rollback Rolls the schema back to ... +db:schema:cache:clear Clears a db/schema_cache.yml file +db:schema:cache:dump Creates a db/schema_cache.yml file +db:schema:dump Creates a db/schema.rb file ... +db:schema:load Loads a schema.rb file ... +db:seed Loads the seed data ... +db:structure:dump Dumps the database structure ... +db:structure:load Recreates the databases ... +db:version Retrieves the current schema ... +... +restart Restart app by touching ... +tmp:create Creates tmp directories ... +``` Let's create a simple Rails application to step through each of these commands in context. @@ -61,7 +100,7 @@ With no further work, `rails server` will run our new shiny Rails app: ```bash $ cd commandsapp -$ bin/rails server +$ rails server => Booting Puma => Rails 5.1.0 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options @@ -80,7 +119,7 @@ INFO: You can also use the alias "s" to start the server: `rails s`. The server can be run on a different port using the `-p` option. The default development environment can be changed using `-e`. ```bash -$ bin/rails server -e production -p 4000 +$ rails server -e production -p 4000 ``` The `-b` option binds Rails to the specified IP, by default it is localhost. You can run a server as a daemon by passing a `-d` option. @@ -92,7 +131,7 @@ The `rails generate` command uses templates to create a whole lot of things. Run INFO: You can also use the alias "g" to invoke the generator command: `rails g`. ```bash -$ bin/rails generate +$ rails generate Usage: rails generate GENERATOR [args] [options] ... @@ -118,7 +157,7 @@ Let's make our own controller with the controller generator. But what command sh INFO: All Rails console utilities have help text. As with most *nix utilities, you can try adding `--help` or `-h` to the end, for example `rails server --help`. ```bash -$ bin/rails generate controller +$ rails generate controller Usage: rails generate controller NAME [action action] [options] ... @@ -144,7 +183,7 @@ Example: The controller generator is expecting parameters in the form of `generate controller ControllerName action1 action2`. Let's make a `Greetings` controller with an action of **hello**, which will say something nice to us. ```bash -$ bin/rails generate controller Greetings hello +$ rails generate controller Greetings hello create app/controllers/greetings_controller.rb route get "greetings/hello" invoke erb @@ -161,7 +200,7 @@ $ bin/rails generate controller Greetings hello create app/assets/stylesheets/greetings.scss ``` -What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a JavaScript file and a stylesheet file. +What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a JavaScript file, and a stylesheet file. Check out the controller and modify it a little (in `app/controllers/greetings_controller.rb`): @@ -183,7 +222,7 @@ Then the view, to display our message (in `app/views/greetings/hello.html.erb`): Fire up your server using `rails server`. ```bash -$ bin/rails server +$ rails server => Booting Puma... ``` @@ -194,7 +233,7 @@ INFO: With a normal, plain-old Rails application, your URLs will generally follo Rails comes with a generator for data models too. ```bash -$ bin/rails generate model +$ rails generate model Usage: rails generate model NAME [field[:type][:index] field[:type][:index]] [options] @@ -217,7 +256,7 @@ But instead of generating a model directly (which we'll be doing later), let's s We will set up a simple resource called "HighScore" that will keep track of our highest score on video games we play. ```bash -$ bin/rails generate scaffold HighScore game:string score:integer +$ rails generate scaffold HighScore game:string score:integer invoke active_record create db/migrate/20130717151933_create_high_scores.rb create app/models/high_score.rb @@ -255,10 +294,10 @@ $ bin/rails generate scaffold HighScore game:string score:integer The generator checks that there exist the directories for models, controllers, helpers, layouts, functional and unit tests, stylesheets, creates the views, controller, model and database migration for HighScore (creating the `high_scores` table and fields), takes care of the route for the **resource**, and new tests for everything. -The migration requires that we **migrate**, that is, run some Ruby code (living in that `20130717151933_create_high_scores.rb`) to modify the schema of our database. Which database? The SQLite3 database that Rails will create for you when we run the `bin/rails db:migrate` command. We'll talk more about bin/rails in-depth in a little while. +The migration requires that we **migrate**, that is, run some Ruby code (living in that `20130717151933_create_high_scores.rb`) to modify the schema of our database. Which database? The SQLite3 database that Rails will create for you when we run the `rails db:migrate` command. We'll talk more about that command below. ```bash -$ bin/rails db:migrate +$ rails db:migrate == CreateHighScores: migrating =============================================== -- create_table(:high_scores) -> 0.0017s @@ -270,13 +309,13 @@ about code. In unit testing, we take a little part of code, say a method of a mo and test its inputs and outputs. Unit tests are your friend. The sooner you make peace with the fact that your quality of life will drastically increase when you unit test your code, the better. Seriously. Please visit -[the testing guide](http://guides.rubyonrails.org/testing.html) for an in-depth +[the testing guide](https://guides.rubyonrails.org/testing.html) for an in-depth look at unit testing. Let's see the interface Rails created for us. ```bash -$ bin/rails server +$ rails server ``` Go to your browser and open [http://localhost:3000/high_scores](http://localhost:3000/high_scores), now we can create new high scores (55,160 on Space Invaders!) @@ -290,13 +329,13 @@ INFO: You can also use the alias "c" to invoke the console: `rails c`. You can specify the environment in which the `console` command should operate. ```bash -$ bin/rails console -e staging +$ rails console -e staging ``` If you wish to test out some code without changing any data, you can do that by invoking `rails console --sandbox`. ```bash -$ bin/rails console --sandbox +$ rails console --sandbox Loading development environment in sandbox (Rails 5.1.0) Any modifications you make will be rolled back on exit irb(main):001:0> @@ -329,7 +368,7 @@ With the `helper` method it is possible to access Rails and your application's h ### `rails dbconsole` -`rails dbconsole` figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL (including MariaDB), PostgreSQL and SQLite3. +`rails dbconsole` figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL (including MariaDB), PostgreSQL, and SQLite3. INFO: You can also use the alias "db" to invoke the dbconsole: `rails db`. @@ -338,7 +377,7 @@ INFO: You can also use the alias "db" to invoke the dbconsole: `rails db`. `runner` runs Ruby code in the context of Rails non-interactively. For instance: ```bash -$ bin/rails runner "Model.long_running_method" +$ rails runner "Model.long_running_method" ``` INFO: You can also use the alias "r" to invoke the runner: `rails r`. @@ -346,13 +385,13 @@ INFO: You can also use the alias "r" to invoke the runner: `rails r`. You can specify the environment in which the `runner` command should operate using the `-e` switch. ```bash -$ bin/rails runner -e staging "Model.long_running_method" +$ rails runner -e staging "Model.long_running_method" ``` You can even execute ruby code written in a file with runner. ```bash -$ bin/rails runner lib/code_to_be_run.rb +$ rails runner lib/code_to_be_run.rb ``` ### `rails destroy` @@ -362,7 +401,7 @@ Think of `destroy` as the opposite of `generate`. It'll figure out what generate INFO: You can also use the alias "d" to invoke the destroy command: `rails d`. ```bash -$ bin/rails generate model Oops +$ rails generate model Oops invoke active_record create db/migrate/20120528062523_create_oops.rb create app/models/oops.rb @@ -371,7 +410,7 @@ $ bin/rails generate model Oops create test/fixtures/oops.yml ``` ```bash -$ bin/rails destroy model Oops +$ rails destroy model Oops invoke active_record remove db/migrate/20120528062523_create_oops.rb remove app/models/oops.rb @@ -380,56 +419,12 @@ $ bin/rails destroy model Oops remove test/fixtures/oops.yml ``` -bin/rails ---------- - -Since Rails 5.0+ has rake commands built into the rails executable, `bin/rails` is the new default for running commands. - -You can get a list of bin/rails tasks available to you, which will often depend on your current directory, by typing `bin/rails --help`. Each task has a description, and should help you find the thing you need. - -```bash -$ bin/rails --help -Usage: rails COMMAND [ARGS] - -The most common rails commands are: -generate Generate new code (short-cut alias: "g") -console Start the Rails console (short-cut alias: "c") -server Start the Rails server (short-cut alias: "s") -... - -All commands can be run with -h (or --help) for more information. - -In addition to those commands, there are: -about List versions of all Rails ... -assets:clean[keep] Remove old compiled assets -assets:clobber Remove compiled assets -assets:environment Load asset compile environment -assets:precompile Compile all the assets ... -... -db:fixtures:load Loads fixtures into the ... -db:migrate Migrate the database ... -db:migrate:status Display status of migrations -db:rollback Rolls the schema back to ... -db:schema:cache:clear Clears a db/schema_cache.yml file -db:schema:cache:dump Creates a db/schema_cache.yml file -db:schema:dump Creates a db/schema.rb file ... -db:schema:load Loads a schema.rb file ... -db:seed Loads the seed data ... -db:structure:dump Dumps the database structure ... -db:structure:load Recreates the databases ... -db:version Retrieves the current schema ... -... -restart Restart app by touching ... -tmp:create Creates tmp directories ... -``` -INFO: You can also use `bin/rails -T` to get the list of tasks. - -### `about` +### `rails about` -`bin/rails about` gives information about version numbers for Ruby, RubyGems, Rails, the Rails subcomponents, your application's folder, the current Rails environment name, your app's database adapter, and schema version. It is useful when you need to ask for help, check if a security patch might affect you, or when you need some stats for an existing Rails installation. +`rails about` gives information about version numbers for Ruby, RubyGems, Rails, the Rails subcomponents, your application's folder, the current Rails environment name, your app's database adapter, and schema version. It is useful when you need to ask for help, check if a security patch might affect you, or when you need some stats for an existing Rails installation. ```bash -$ bin/rails about +$ rails about About your application's environment Rails version 6.0.0 Ruby version 2.5.0 (x86_64-linux) @@ -443,102 +438,127 @@ Database adapter sqlite3 Database schema version 20180205173523 ``` -### `assets` +### `rails assets:` -You can precompile the assets in `app/assets` using `bin/rails assets:precompile`, and remove older compiled assets using `bin/rails assets:clean`. The `assets:clean` task allows for rolling deploys that may still be linking to an old asset while the new assets are being built. +You can precompile the assets in `app/assets` using `rails assets:precompile`, and remove older compiled assets using `rails assets:clean`. The `assets:clean` command allows for rolling deploys that may still be linking to an old asset while the new assets are being built. -If you want to clear `public/assets` completely, you can use `bin/rails assets:clobber`. +If you want to clear `public/assets` completely, you can use `rails assets:clobber`. -### `db` +### `rails db:` -The most common tasks of the `db:` bin/rails namespace are `migrate` and `create`, and it will pay off to try out all of the migration bin/rails tasks (`up`, `down`, `redo`, `reset`). `bin/rails db:version` is useful when troubleshooting, telling you the current version of the database. +The most common commands of the `db:` rails namespace are `migrate` and `create`, and it will pay off to try out all of the migration rails commands (`up`, `down`, `redo`, `reset`). `rails db:version` is useful when troubleshooting, telling you the current version of the database. More information about migrations can be found in the [Migrations](active_record_migrations.html) guide. -### `notes` +### `rails notes` + +`rails notes` searches through your code for comments beginning with a specific keyword. You can refer to `rails notes --help` for information about usage. -`bin/rails notes` will search through your code for comments beginning with FIXME, OPTIMIZE or TODO. The search is done in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js` and `.erb` for both default and custom annotations. +By default, it will search in `app`, `config`, `db`, `lib`, and `test` directories for FIXME, OPTIMIZE, and TODO annotations in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js`, and `.erb`. ```bash -$ bin/rails notes -(in /home/foobar/commandsapp) +$ rails notes app/controllers/admin/users_controller.rb: * [ 20] [TODO] any other way to do this? * [132] [FIXME] high priority for next deploy -app/models/school.rb: +lib/school.rb: * [ 13] [OPTIMIZE] refactor this code to make it faster * [ 17] [FIXME] ``` -You can add support for new file extensions using `config.annotations.register_extensions` option, which receives a list of the extensions with its corresponding regex to match it up. - -```ruby -config.annotations.register_extensions("scss", "sass", "less") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } -``` +#### Annotations -If you are looking for a specific annotation, say FIXME, you can use `bin/rails notes:fixme`. Note that you have to lower case the annotation's name. +You can pass specific annotations by using the `--annotations` argument. By default, it will search for FIXME, OPTIMIZE, and TODO. +Note that annotations are case sensitive. ```bash -$ bin/rails notes:fixme -(in /home/foobar/commandsapp) +$ rails notes --annotations FIXME RELEASE app/controllers/admin/users_controller.rb: - * [132] high priority for next deploy + * [101] [RELEASE] We need to look at this before next release + * [132] [FIXME] high priority for next deploy -app/models/school.rb: - * [ 17] +lib/school.rb: + * [ 17] [FIXME] ``` -You can also use custom annotations in your code and list them using `bin/rails notes:custom` by specifying the annotation using an environment variable `ANNOTATION`. +#### Directories + +You can add more default directories to search from by using `config.annotations.register_directories`. It receives a list of directory names. + +```ruby +config.annotations.register_directories("spec", "vendor") +``` ```bash -$ bin/rails notes:custom ANNOTATION=BUG -(in /home/foobar/commandsapp) -app/models/article.rb: - * [ 23] Have to fix this one before pushing! +$ rails notes +app/controllers/admin/users_controller.rb: + * [ 20] [TODO] any other way to do this? + * [132] [FIXME] high priority for next deploy + +lib/school.rb: + * [ 13] [OPTIMIZE] Refactor this code to make it faster + * [ 17] [FIXME] + +spec/models/user_spec.rb: + * [122] [TODO] Verify the user that has a subscription works + +vendor/tools.rb: + * [ 56] [TODO] Get rid of this dependency ``` -NOTE. When using specific annotations and custom annotations, the annotation name (FIXME, BUG etc) is not displayed in the output lines. +#### Extensions -By default, `rails notes` will look in the `app`, `config`, `db`, `lib` and `test` directories. If you would like to search other directories, you can configure them using `config.annotations.register_directories` option. +You can add more default file extensions to search from by using `config.annotations.register_extensions`. It receives a list of extensions with its corresponding regex to match it up. ```ruby -config.annotations.register_directories("spec", "vendor") +config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } ``` -You can also provide them as a comma separated list in the environment variable `SOURCE_ANNOTATION_DIRECTORIES`. - ```bash -$ export SOURCE_ANNOTATION_DIRECTORIES='spec,vendor' -$ bin/rails notes -(in /home/foobar/commandsapp) -app/models/user.rb: - * [ 35] [FIXME] User should have a subscription at this point +$ rails notes +app/controllers/admin/users_controller.rb: + * [ 20] [TODO] any other way to do this? + * [132] [FIXME] high priority for next deploy + +app/assets/stylesheets/application.css.sass: + * [ 34] [TODO] Use pseudo element for this class + +app/assets/stylesheets/application.css.scss: + * [ 1] [TODO] Split into multiple components + +lib/school.rb: + * [ 13] [OPTIMIZE] Refactor this code to make it faster + * [ 17] [FIXME] + spec/models/user_spec.rb: * [122] [TODO] Verify the user that has a subscription works + +vendor/tools.rb: + * [ 56] [TODO] Get rid of this dependency ``` -### `routes` +### `rails routes` `rails routes` will list all of your defined routes, which is useful for tracking down routing problems in your app, or giving you a good overview of the URLs in an app you're trying to get familiar with. -### `test` +### `rails test` INFO: A good description of unit testing in Rails is given in [A Guide to Testing Rails Applications](testing.html) -Rails comes with a test suite called Minitest. Rails owes its stability to the use of tests. The tasks available in the `test:` namespace helps in running the different tests you will hopefully write. +Rails comes with a test suite called Minitest. Rails owes its stability to the use of tests. The commands available in the `test:` namespace helps in running the different tests you will hopefully write. -### `tmp` +### `rails tmp:` The `Rails.root/tmp` directory is, like the *nix /tmp directory, the holding place for temporary files like process id files and cached actions. -The `tmp:` namespaced tasks will help you clear and create the `Rails.root/tmp` directory: +The `tmp:` namespaced commands will help you clear and create the `Rails.root/tmp` directory: * `rails tmp:cache:clear` clears `tmp/cache`. * `rails tmp:sockets:clear` clears `tmp/sockets`. * `rails tmp:screenshots:clear` clears `tmp/screenshots`. -* `rails tmp:clear` clears all cache, sockets and screenshot files. -* `rails tmp:create` creates tmp directories for cache, sockets and pids. +* `rails tmp:clear` clears all cache, sockets, and screenshot files. +* `rails tmp:create` creates tmp directories for cache, sockets, and pids. ### Miscellaneous @@ -550,7 +570,7 @@ The `tmp:` namespaced tasks will help you clear and create the `Rails.root/tmp` Custom rake tasks have a `.rake` extension and are placed in `Rails.root/lib/tasks`. You can create these custom rake tasks with the -`bin/rails generate task` command. +`rails generate task` command. ```ruby desc "I am short, but comprehensive description for my cool task" @@ -582,12 +602,12 @@ end Invocation of the tasks will look like: ```bash -$ bin/rails task_name -$ bin/rails "task_name[value 1]" # entire argument string should be quoted -$ bin/rails db:nothing +$ rails task_name +$ rails "task_name[value 1]" # entire argument string should be quoted +$ rails db:nothing ``` -NOTE: If your need to interact with your application models, perform database queries and so on, your task should depend on the `environment` task, which will load your application code. +NOTE: If your need to interact with your application models, perform database queries, and so on, your task should depend on the `environment` task, which will load your application code. The Rails Advanced Command Line ------------------------------- @@ -633,9 +653,9 @@ $ cat config/database.yml # # Install the pg driver: # gem install pg -# On OS X with Homebrew: +# On macOS with Homebrew: # gem install pg -- --with-pg-config=/usr/local/bin/pg_config -# On OS X with MacPorts: +# On macOS with MacPorts: # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config # On Windows: # gem install pg @@ -649,7 +669,7 @@ default: &default adapter: postgresql encoding: unicode # For details on connection pooling, see Rails configuration guide - # http://guides.rubyonrails.org/configuring.html#database-pooling + # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 368b74f708..6e4f1f9648 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Configuring Rails Applications ============================== @@ -86,7 +86,7 @@ application. Accepts a valid week day symbol (e.g. `:monday`). end ``` -* `config.eager_load` when `true`, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks and any other registered namespace. +* `config.eager_load` when `true`, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks, and any other registered namespace. * `config.eager_load_namespaces` registers namespaces that are eager loaded when `config.eager_load` is `true`. All namespaces in the list must respond to the `eager_load!` method. @@ -165,7 +165,7 @@ pipeline is enabled. It is set to `true` by default. * `config.assets.precompile` allows you to specify additional assets (other than `application.css` and `application.js`) which are to be precompiled when `rake assets:precompile` is run. -* `config.assets.unknown_asset_fallback` allows you to modify the behavior of the asset pipeline when an asset is not in the pipeline, if you use sprockets-rails 3.2.0 or newer. Defaults to `true`. +* `config.assets.unknown_asset_fallback` allows you to modify the behavior of the asset pipeline when an asset is not in the pipeline, if you use sprockets-rails 3.2.0 or newer. Defaults to `false`. * `config.assets.prefix` defines the prefix where assets are served from. Defaults to `/assets`. @@ -305,6 +305,10 @@ All these configuration options are delegated to the `I18n` library. config.i18n.fallbacks.map = { az: :tr, da: [:de, :en] } ``` +### Configuring Active Model + +* `config.active_model.i18n_full_message` is a boolean value which controls whether the `full_message` error format can be overridden at the attribute or model level in the locale files. This is `false` by default. + ### Configuring Active Record `config.active_record` includes a variety of configuration options: @@ -370,7 +374,7 @@ All these configuration options are delegated to the `I18n` library. Defaults to `false`. * `config.active_record.use_schema_cache_dump` enables users to get schema cache information - from `db/schema_cache.yml` (generated by `bin/rails db:schema:cache:dump`), instead of + from `db/schema_cache.yml` (generated by `rails db:schema:cache:dump`), instead of having to send a query to the database to get this information. Defaults to `true`. @@ -400,10 +404,16 @@ by adding the following to your `application.rb` file: Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true ``` -The schema dumper adds one additional configuration option: +The schema dumper adds two additional configuration options: * `ActiveRecord::SchemaDumper.ignore_tables` accepts an array of tables that should _not_ be included in any generated schema file. +* `ActiveRecord::SchemaDumper.fk_ignore_pattern` allows setting a different regular + expression that will be used to decide whether a foreign key's name should be + dumped to db/schema.rb or not. By default, foreign key names starting with + `fk_rails_` are not exported to the database schema dump. + Defaults to `/^fk_rails_[0-9a-f]{10}$/`. + ### Configuring Action Controller `config.action_controller` includes a number of configuration settings: @@ -594,6 +604,13 @@ Defaults to `'signed cookie'`. * `config.action_view.default_enforce_utf8` determines whether forms are generated with a hidden tag that forces older versions of Internet Explorer to submit forms encoded in UTF-8. This defaults to `false`. +* `config.action_view.finalize_compiled_template_methods` determines + whether the methods on `ActionView::CompiledTemplates` that templates + compile themselves to are removed when template instances are + destroyed by the garbage collector. This helps prevent memory leaks in + development mode, but for large test suites, disabling this option in + the test environment can improve performance. This defaults to `true`. + ### Configuring Action Mailer There are a number of settings available on `config.action_mailer`: @@ -650,6 +667,12 @@ There are a number of settings available on `config.action_mailer`: config.action_mailer.interceptors = ["MailInterceptor"] ``` +* `config.action_mailer.preview_interceptors` registers interceptors which will be called before mail is previewed. + + ```ruby + config.action_mailer.preview_interceptors = ["MyPreviewMailInterceptor"] + ``` + * `config.action_mailer.preview_path` specifies the location of mailer previews. ```ruby @@ -684,6 +707,8 @@ There are a few configuration options available in Active Support: * `config.active_support.use_sha1_digests` specifies whether to use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. Defaults to false. +* `config.active_support.use_authenticated_message_encryption` specifies whether to use AES-256-GCM authenticated encryption as the default cipher for encrypting messages instead of AES-256-CBC. This is false by default, but enabled when loading defaults for Rails 5.2. + * `ActiveSupport::Logger.silencer` is set to `false` to disable the ability to silence logging in a block. The default is `true`. * `ActiveSupport::Cache::Store.logger` specifies the logger to use within cache store operations. @@ -765,6 +790,8 @@ normal Rails server. `config.active_storage` provides the following configuration options: +* `config.active_storage.variant_processor` accepts a symbol `:mini_magick` or `:vips`, specifying whether variant transformations will be performed with MiniMagick or ruby-vips. The default is `:mini_magick`. + * `config.active_storage.analyzers` accepts an array of classes indicating the analyzers available for Active Storage blobs. The default is `[ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer]`. The former can extract width and height of an image blob; the latter can extract width, height, duration, angle, and aspect ratio of a video blob. * `config.active_storage.previewers` accepts an array of classes indicating the image previewers available in Active Storage blobs. The default is `[ActiveStorage::Previewer::PDFPreviewer, ActiveStorage::Previewer::VideoPreviewer]`. The former can generate a thumbnail from the first page of a PDF blob; the latter from the relevant frame of a video blob. @@ -778,7 +805,7 @@ normal Rails server. config.active_storage.paths[:ffprobe] = '/usr/local/bin/ffprobe' ``` -* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/vnd.adobe.photoshop)`. +* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/vnd.adobe.photoshop image/vnd.microsoft.icon)`. * `config.active_storage.content_types_to_serve_as_binary` accepts an array of strings indicating the content types that Active Storage will always serve as an attachment, rather than inline. The default is `%w(text/html text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml)`. @@ -786,15 +813,22 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla * `config.active_storage.queue` can be used to set the name of the Active Job queue used to perform jobs like analyzing the content of a blob or purging a blog. ```ruby - config.active_job.queue = :low_priority + config.active_storage.queue = :low_priority ``` * `config.active_storage.logger` can be used to set the logger used by Active Storage. Accepts a logger conforming to the interface of Log4r or the default Ruby Logger class. ```ruby - config.active_job.logger = ActiveSupport::Logger.new(STDOUT) + config.active_storage.logger = ActiveSupport::Logger.new(STDOUT) ``` +* `config.active_storage.service_urls_expire_in` determines the default expiry of URLs generated by: + * `ActiveStorage::Blob#service_url` + * `ActiveStorage::Blob#service_url_for_direct_upload` + * `ActiveStorage::Variant#service_url` + + The default is 5 minutes. + ### Configuring a Database Just about every Rails application will interact with a database. You can connect to the database by setting an environment variable `ENV['DATABASE_URL']` or by using a configuration file called `config/database.yml`. @@ -873,7 +907,7 @@ development: $ echo $DATABASE_URL postgresql://localhost/my_database -$ bin/rails runner 'puts ActiveRecord::Base.configurations' +$ rails runner 'puts ActiveRecord::Base.configurations' {"development"=>{"adapter"=>"postgresql", "host"=>"localhost", "database"=>"my_database"}} ``` @@ -890,7 +924,7 @@ development: $ echo $DATABASE_URL postgresql://localhost/my_database -$ bin/rails runner 'puts ActiveRecord::Base.configurations' +$ rails runner 'puts ActiveRecord::Base.configurations' {"development"=>{"adapter"=>"postgresql", "host"=>"localhost", "database"=>"my_database", "pool"=>5}} ``` @@ -906,7 +940,7 @@ development: $ echo $DATABASE_URL postgresql://localhost/my_database -$ bin/rails runner 'puts ActiveRecord::Base.configurations' +$ rails runner 'puts ActiveRecord::Base.configurations' {"development"=>{"adapter"=>"sqlite3", "database"=>"NOT_my_database"}} ``` @@ -1191,7 +1225,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `i18n.callbacks`: In the development environment, sets up a `to_prepare` callback which will call `I18n.reload!` if any of the locales have changed since the last request. In production mode this callback will only run on the first request. -* `active_support.deprecation_behavior`: Sets up deprecation reporting for environments, defaulting to `:log` for development, `:notify` for production and `:stderr` for test. If a value isn't set for `config.active_support.deprecation` then this initializer will prompt the user to configure this line in the current environment's `config/environments` file. Can be set to an array of values. +* `active_support.deprecation_behavior`: Sets up deprecation reporting for environments, defaulting to `:log` for development, `:notify` for production, and `:stderr` for test. If a value isn't set for `config.active_support.deprecation` then this initializer will prompt the user to configure this line in the current environment's `config/environments` file. Can be set to an array of values. * `active_support.initialize_time_zone`: Sets the default time zone for the application based on the `config.time_zone` setting, which defaults to "UTC". @@ -1250,23 +1284,23 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `add_routing_paths`: Loads (by default) all `config/routes.rb` files (in the application and railties, including engines) and sets up the routes for the application. -* `add_locales`: Adds the files in `config/locales` (from the application, railties and engines) to `I18n.load_path`, making available the translations in these files. +* `add_locales`: Adds the files in `config/locales` (from the application, railties, and engines) to `I18n.load_path`, making available the translations in these files. -* `add_view_paths`: Adds the directory `app/views` from the application, railties and engines to the lookup path for view files for the application. +* `add_view_paths`: Adds the directory `app/views` from the application, railties, and engines to the lookup path for view files for the application. * `load_environment_config`: Loads the `config/environments` file for the current environment. -* `prepend_helpers_path`: Adds the directory `app/helpers` from the application, railties and engines to the lookup path for helpers for the application. +* `prepend_helpers_path`: Adds the directory `app/helpers` from the application, railties, and engines to the lookup path for helpers for the application. -* `load_config_initializers`: Loads all Ruby files from `config/initializers` in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded. +* `load_config_initializers`: Loads all Ruby files from `config/initializers` in the application, railties, and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded. * `engines_blank_point`: Provides a point-in-initialization to hook into if you wish to do anything before engines are loaded. After this point, all railtie and engine initializers are run. -* `add_generator_templates`: Finds templates for generators at `lib/templates` for the application, railties and engines and adds these to the `config.generators.templates` setting, which will make the templates available for all generators to reference. +* `add_generator_templates`: Finds templates for generators at `lib/templates` for the application, railties, and engines and adds these to the `config.generators.templates` setting, which will make the templates available for all generators to reference. * `ensure_autoload_once_paths_as_subset`: Ensures that the `config.autoload_once_paths` only contains paths from `config.autoload_paths`. If it contains extra paths, then an exception will be raised. -* `add_to_prepare_blocks`: The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be run per request in development, or before the first request in production. +* `add_to_prepare_blocks`: The block for every `config.to_prepare` call in the application, a railtie, or engine is added to the `to_prepare` callbacks for Action Dispatch which will be run per request in development, or before the first request in production. * `add_builtin_route`: If the application is running under the development environment then this will append the route for `rails/info/properties` to the application routes. This route provides the detailed information such as Rails and Ruby version for `public/index.html` in a default Rails application. @@ -1274,7 +1308,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `eager_load!`: If `config.eager_load` is `true`, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`. -* `finisher_hook`: Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties and engines. +* `finisher_hook`: Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties, and engines. * `set_routes_reloader_hook`: Configures Action Dispatch to reload the routes file using `ActiveSupport::Callbacks.to_run`. @@ -1366,7 +1400,7 @@ Search Engines Indexing ----------------------- Sometimes, you may want to prevent some pages of your application to be visible -on search sites like Google, Bing, Yahoo or Duck Duck Go. The robots that index +on search sites like Google, Bing, Yahoo, or Duck Duck Go. The robots that index these sites will first analyze the `http://your-site.com/robots.txt` file to know which pages it is allowed to index. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index c1668f989b..3147b00f3b 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Contributing to Ruby on Rails ============================= @@ -23,7 +23,7 @@ README](https://github.com/rails/rails/blob/master/README.md), everyone interact Reporting an Issue ------------------ -Ruby on Rails uses [GitHub Issue Tracking](https://github.com/rails/rails/issues) to track issues (primarily bugs and contributions of new code). If you've found a bug in Ruby on Rails, this is the place to start. You'll need to create a (free) GitHub account in order to submit an issue, to comment on them or to create pull requests. +Ruby on Rails uses [GitHub Issue Tracking](https://github.com/rails/rails/issues) to track issues (primarily bugs and contributions of new code). If you've found a bug in Ruby on Rails, this is the place to start. You'll need to create a (free) GitHub account in order to submit an issue, to comment on them, or to create pull requests. NOTE: Bugs in the most recent released version of Ruby on Rails are likely to get the most attention. Also, the Rails core team is always interested in feedback from those who can take the time to test _edge Rails_ (the code for the version of Rails that is currently under development). Later in this guide, you'll find out how to get edge Rails for testing. @@ -37,7 +37,7 @@ Then, don't get your hopes up! Unless you have a "Code Red, Mission Critical, th ### Create an Executable Test Case -Having a way to reproduce your issue will be very helpful for others to help confirm, investigate and ultimately fix your issue. You can do this by providing an executable test case. To make this process easier, we have prepared several bug report templates for you to use as a starting point: +Having a way to reproduce your issue will be very helpful for others to help confirm, investigate, and ultimately fix your issue. You can do this by providing an executable test case. To make this process easier, we have prepared several bug report templates for you to use as a starting point: * Template for Active Record (models, database) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_master.rb) * Template for testing Active Record (migration) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_migrations_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_migrations_master.rb) @@ -132,7 +132,7 @@ Contributing to the Rails Documentation Ruby on Rails has two main sets of documentation: the guides, which help you learn about Ruby on Rails, and the API, which serves as a reference. -You can help improve the Rails guides by making them more coherent, consistent or readable, adding missing information, correcting factual errors, fixing typos, or bringing them up to date with the latest edge Rails. +You can help improve the Rails guides by making them more coherent, consistent, or readable, adding missing information, correcting factual errors, fixing typos, or bringing them up to date with the latest edge Rails. To do so, make changes to Rails guides source files (located [here](https://github.com/rails/rails/tree/master/guides/source) on GitHub). Then open a pull request to apply your changes to master branch. @@ -374,17 +374,11 @@ You can invoke `test_jdbcmysql`, `test_jdbcsqlite3` or `test_jdbcpostgresql` als The test suite runs with warnings enabled. Ideally, Ruby on Rails should issue no warnings, but there may be a few, as well as some from third-party libraries. Please ignore (or fix!) them, if any, and submit patches that do not issue new warnings. -If you are sure about what you are doing and would like to have a more clear output, there's a way to override the flag: - -```bash -$ RUBYOPT=-W0 bundle exec rake test -``` - ### Updating the CHANGELOG The CHANGELOG is an important part of every release. It keeps the list of changes for every Rails version. -You should add an entry **to the top** of the CHANGELOG of the framework that you modified if you're adding or removing a feature, committing a bug fix or adding deprecation notices. Refactorings and documentation changes generally should not go to the CHANGELOG. +You should add an entry **to the top** of the CHANGELOG of the framework that you modified if you're adding or removing a feature, committing a bug fix, or adding deprecation notices. Refactorings and documentation changes generally should not go to the CHANGELOG. A CHANGELOG entry should summarize what was changed and should end with the author's name. You can use multiple lines if you need more space and you can attach code examples indented with 4 spaces. If a change is related to a specific issue, you should attach the issue's number. Here is an example CHANGELOG entry: @@ -398,7 +392,7 @@ A CHANGELOG entry should summarize what was changed and should end with the auth end end - You can continue after the code example and you can attach issue number. GH#1234 + You can continue after the code example and you can attach issue number. Fixes #1234. *Your Name* ``` diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb deleted file mode 100644 index 5adbd12ac0..0000000000 --- a/guides/source/credits.html.erb +++ /dev/null @@ -1,80 +0,0 @@ -<% content_for :page_title do %> -Ruby on Rails Guides: Credits -<% end %> - -<% content_for :header_section do %> -<h2>Credits</h2> - -<p>We'd like to thank the following people for their tireless contributions to this project.</p> - -<% end %> - -<h3 class="section">Rails Guides Reviewers</h3> - -<%= author('Vijay Dev', 'vijaydev', 'vijaydev.jpg') do %> - Vijayakumar, found as Vijay Dev on the web, is a web applications developer and an open source enthusiast who lives in Chennai, India. He started using Rails in 2009 and began actively contributing to Rails documentation in late 2010. He <a href="https://twitter.com/vijay_dev">tweets</a> a lot and also <a href="http://vijaydev.wordpress.com">blogs</a>. -<% end %> - -<%= author('Xavier Noria', 'fxn', 'fxn.png') do %> - Xavier Noria has been into Ruby on Rails since 2005. He is a Rails core team member and enjoys combining his passion for Rails and his past life as a proofreader of math textbooks. Xavier is currently an independent Ruby on Rails consultant. Oh, he also <a href="http://twitter.com/fxn">tweets</a> and can be found everywhere as "fxn". -<% end %> - -<h3 class="section">Rails Guides Designers</h3> - -<%= author('Jason Zimdars', 'jz') do %> - Jason Zimdars is an experienced creative director and web designer who has lead UI and UX design for numerous websites and web applications. You can see more of his design and writing at <a href="http://www.thinkcage.com/">Thinkcage.com</a> or follow him on <a href="https://twitter.com/jasonzimdars">Twitter</a>. -<% end %> - -<h3 class="section">Rails Guides Authors</h3> - -<%= author('Ryan Bigg', 'radar', 'radar.png') do %> - Ryan Bigg works as a Rails developer at <a href="http://marketplacer.com">Marketplacer</a> and has been working with Rails since 2006. He's the author of <a href="https://leanpub.com/multi-tenancy-rails">Multi Tenancy With Rails</a> and co-author of <a href="http://manning.com/bigg2">Rails 4 in Action</a>. He's written many gems which can be seen on <a href="https://github.com/radar">his GitHub page</a> and he also tweets prolifically as <a href="http://twitter.com/ryanbigg">@ryanbigg</a>. -<% end %> - -<%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %> -Oscar Del Ben is a software engineer at <a href="http://www.businessinsider.com/google-buys-wildfire-2012-8">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">GitHub account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>. - <% end %> - -<%= author('Frederick Cheung', 'fcheung') do %> - Frederick Cheung is Chief Wizard at Texperts where he has been using Rails since 2006. He is based in Cambridge (UK) and when not consuming fine ales he blogs at <a href="http://www.spacevatican.org">spacevatican.org</a>. -<% end %> - -<%= author('Tore Darell', 'toretore') do %> - Tore Darell is an independent developer based in Menton, France who specialises in cruft-free web applications using Ruby, Rails and unobtrusive JavaScript. You can follow him on <a href="http://twitter.com/toretore">Twitter</a>. -<% end %> - -<%= author('Jeff Dean', 'zilkey') do %> - Jeff Dean is a software engineer with <a href="http://pivotallabs.com">Pivotal Labs</a>. -<% end %> - -<%= author('Mike Gunderloy', 'mgunderloy') do %> - Mike Gunderloy is a consultant with <a href="http://www.actionrails.com">ActionRails</a>. He brings 25 years of experience in a variety of languages to bear on his current work with Rails. His near-daily links and other blogging can be found at <a href="http://afreshcup.com">A Fresh Cup</a> and he <a href="http://twitter.com/MikeG1">twitters</a> too much. -<% end %> - -<%= author('Mikel Lindsaar', 'raasdnil') do %> - Mikel Lindsaar has been working with Rails since 2006 and is the author of the Ruby <a href="https://github.com/mikel/mail">Mail gem</a> and core contributor (he helped re-write Action Mailer's API). Mikel is the founder of <a href="http://rubyx.com/">RubyX</a>, has a <a href="http://lindsaar.net/">blog</a> and <a href="http://twitter.com/raasdnil">tweets</a>. -<% end %> - -<%= author('Cássio Marques', 'cmarques') do %> - Cássio Marques is a Brazilian software developer working with different programming languages such as Ruby, JavaScript, CPP and Java, as an independent consultant. He blogs at <a href="http://cassiomarques.wordpress.com">/* CODIFICANDO */</a>, which is mainly written in Portuguese, but will soon get a new section for posts with English translation. -<% end %> - -<%= author('James Miller', 'bensie') do %> - James Miller is a software developer for <a href="http://www.jk-tech.com">JK Tech</a> in San Diego, CA. You can find James on GitHub, Gmail, Twitter, and Freenode as "bensie". -<% end %> - -<%= author('Pratik Naik', 'lifo') do %> - Pratik Naik is a Ruby on Rails developer at <a href="https://basecamp.com/">Basecamp</a> and maintains a blog at <a href="http://m.onkey.org">has_many :bugs, :through => :rails</a>. He also has a semi-active <a href="http://twitter.com/lifo">twitter account</a>. -<% end %> - -<%= author('Emilio Tagua', 'miloops') do %> - Emilio Tagua —a.k.a. miloops— is an Argentinian entrepreneur, developer, open source contributor and Rails evangelist. Cofounder of <a href="http://eventioz.com">Eventioz</a>. He has been using Rails since 2006 and contributing since early 2008. Can be found at gmail, twitter, freenode, everywhere as "miloops". -<% end %> - -<%= author('Heiko Webers', 'hawe') do %> - Heiko Webers is the founder of <a href="http://www.bauland42.de">bauland42</a>, a German web application security consulting and development company focused on Ruby on Rails. He blogs at the <a href="http://www.rorsecurity.info">Ruby on Rails Security Project</a>. After 10 years of desktop application development, Heiko has rarely looked back. -<% end %> - -<%= author('Akshay Surve', 'startupjockey', 'akshaysurve.jpg') do %> - Akshay Surve is the Founder at <a href="http://www.deltax.com">DeltaX</a>, hackathon specialist, a midnight code junkie and occasionally writes prose. You can connect with him on <a href="https://twitter.com/akshaysurve">Twitter</a>, <a href="http://www.linkedin.com/in/akshaysurve">Linkedin</a>, <a href="http://www.akshaysurve.com/">Personal Blog</a> or <a href="http://www.quora.com/Akshay-Surve">Quora</a>. -<% end %> diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 07c78be3db..88d205e1ab 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Debugging Rails Applications ============================ @@ -147,7 +147,7 @@ TIP: The default Rails log level is `debug` in all environments. ### Sending Messages -To write in the current log use the `logger.(debug|info|warn|error|fatal)` method from within a controller, model or mailer: +To write in the current log use the `logger.(debug|info|warn|error|fatal)` method from within a controller, model, or mailer: ```ruby logger.debug "Person attributes hash: #{@person.attributes.inspect}" @@ -485,7 +485,7 @@ stack frames. ### Threads -The debugger can list, stop, resume and switch between running threads by using +The debugger can list, stop, resume, and switch between running threads by using the `thread` command (or the abbreviated `th`). This command has a handful of options: @@ -777,7 +777,7 @@ deleted when that breakpoint is reached. * `finish [n]`: execute until the selected stack frame returns. If no frame number is given, the application will run until the currently selected frame returns. The currently selected frame starts out the most-recent frame or 0 if -no frame positioning (e.g up, down or frame) has been performed. If a frame +no frame positioning (e.g up, down, or frame) has been performed. If a frame number is given it will run until the specified frame returns. ### Editing @@ -875,7 +875,7 @@ location of the `console` call; it won't be rendered on the spot of its invocation but next to your HTML content. The console executes pure Ruby code: You can define and instantiate -custom classes, create new models and inspect variables. +custom classes, create new models, and inspect variables. NOTE: Only one console can be rendered per request. Otherwise `web-console` will raise an error on the second `console` invocation. diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 50274d700b..057bcf2c1b 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Development Dependencies Install ================================ @@ -376,3 +376,31 @@ command inside of the `activestorage` directory to install the dependencies: ```bash yarn install ``` + +Extracting previews, tested in ActiveStorage's test suite requires third-party +applications, FFmpeg for video and muPDF for PDFs, and on macOS also XQuartz +and Poppler. Without these applications installed, ActiveStorage tests will +raise errors. + +On macOS you can run: + +```bash +brew install ffmpeg +brew cask install xquartz +brew install mupdf-tools +brew install poppler +``` + +On Ubuntu, you can run: + +```bash +sudo apt-get update && install ffmpeg +sudo apt-get update && install mupdf mupdf-tools +``` + +On Fedora or CentOS, just run: + +```bash +sudo yum install ffmpeg +sudo yum install mupdf +``` diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 5cddf79eeb..4dee34b1e7 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -65,17 +65,13 @@ url: routing.html description: This guide covers the user-facing features of Rails routing. If you want to understand how to use routing in your own Rails applications, start here. - - name: Digging Deeper + name: Other Components documents: - name: Active Support Core Extensions url: active_support_core_extensions.html description: This guide documents the Ruby core extensions defined in Active Support. - - name: Rails Internationalization (I18n) API - url: i18n.html - description: This guide covers how to add internationalization to your applications. Your application will be able to translate content to different languages, change pluralization rules, use correct date formats for each country, and so on. - - name: Action Mailer Basics url: action_mailer_basics.html description: This guide describes how to use Action Mailer to send and receive emails. @@ -88,6 +84,18 @@ url: active_storage_overview.html description: This guide covers how to attach files to your Active Record models. - + name: Action Cable Overview + url: action_cable_overview.html + description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features. + +- + name: Digging Deeper + documents: + - + name: Rails Internationalization (I18n) API + url: i18n.html + description: This guide covers how to add internationalization to your applications. Your application will be able to translate content to different languages, change pluralization rules, use correct date formats for each country, and so on. + - name: Testing Rails Applications url: testing.html description: This is a rather comprehensive guide to the various testing facilities in Rails. It covers everything from 'What is a test?' to Integration Testing. Enjoy. @@ -137,10 +145,6 @@ name: Using Rails for API-only Applications url: api_app.html description: This guide explains how to effectively use Rails to develop a JSON API application. - - - name: Action Cable Overview - url: action_cable_overview.html - description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features. - name: Extending Rails diff --git a/guides/source/engines.md b/guides/source/engines.md index 8d81296fa5..1e93a19c84 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Getting Started with Engines ============================ @@ -188,7 +188,7 @@ inside the application, performing tasks such as adding the `app` directory of the engine to the load path for models, mailers, controllers, and views. The `isolate_namespace` method here deserves special notice. This call is -responsible for isolating the controllers, models, routes and other things into +responsible for isolating the controllers, models, routes, and other things into their own namespace, away from similar components inside the application. Without this, there is a possibility that the engine's components could "leak" into the application, causing unwanted disruption, or that important engine @@ -202,7 +202,7 @@ within the `Engine` class definition. Without it, classes generated in an engine **may** conflict with an application. What this isolation of the namespace means is that a model generated by a call -to `bin/rails g model`, such as `bin/rails g model article`, won't be called `Article`, but +to `rails g model`, such as `rails g model article`, won't be called `Article`, but instead be namespaced and called `Blorgh::Article`. In addition, the table for the model is namespaced, becoming `blorgh_articles`, rather than simply `articles`. Similar to the model namespacing, a controller called `ArticlesController` becomes @@ -313,13 +313,16 @@ The engine that this guide covers provides submitting articles and commenting functionality and follows a similar thread to the [Getting Started Guide](getting_started.html), with some new twists. +NOTE: For this section, make sure to run the commands in the root of the +`blorgh` engine's directory. + ### Generating an Article Resource The first thing to generate for a blog engine is the `Article` model and related controller. To quickly generate this, you can use the Rails scaffold generator. ```bash -$ bin/rails generate scaffold article title:string text:text +$ rails generate scaffold article title:string text:text ``` This command will output this information: @@ -427,7 +430,7 @@ Finally, the assets for this resource are generated in two files: `app/assets/stylesheets/blorgh/articles.css`. You'll see how to use these a little later. -You can see what the engine has so far by running `bin/rails db:migrate` at the root +You can see what the engine has so far by running `rails db:migrate` at the root of our engine to run the migration generated by the scaffold generator, and then running `rails server` in `test/dummy`. When you open `http://localhost:3000/blorgh/articles` you will see the default scaffold that has @@ -461,7 +464,7 @@ rather than visiting `/articles`. This means that instead of Now that the engine can create new articles, it only makes sense to add commenting functionality as well. To do this, you'll need to generate a comment -model, a comment controller and then modify the articles scaffold to display +model, a comment controller, and then modify the articles scaffold to display comments and allow people to create new ones. From the application root, run the model generator. Tell it to generate a @@ -469,7 +472,7 @@ From the application root, run the model generator. Tell it to generate a and `text` text column. ```bash -$ bin/rails generate model Comment article_id:integer text:text +$ rails generate model Comment article_id:integer text:text ``` This will output the following: @@ -489,7 +492,7 @@ called `Blorgh::Comment`. Now run the migration to create our blorgh_comments table: ```bash -$ bin/rails db:migrate +$ rails db:migrate ``` To show the comments on an article, edit `app/views/blorgh/articles/show.html.erb` and @@ -563,7 +566,7 @@ The route now exists, but the controller that this route goes to does not. To create it, run this command from the application root: ```bash -$ bin/rails g controller comments +$ rails g controller comments ``` This will generate the following things: @@ -695,17 +698,17 @@ pre-defined path which may be customizable. The engine contains migrations for the `blorgh_articles` and `blorgh_comments` table which need to be created in the application's database so that the engine's models can query them correctly. To copy these migrations into the -application run the following command from the `test/dummy` directory of your Rails engine: +application run the following command from the application's root: ```bash -$ bin/rails blorgh:install:migrations +$ rails blorgh:install:migrations ``` If you have multiple engines that need migrations copied over, use `railties:install:migrations` instead: ```bash -$ bin/rails railties:install:migrations +$ rails railties:install:migrations ``` This command, when run for the first time, will copy over all the migrations @@ -723,7 +726,7 @@ timestamp (`[timestamp_2]`) will be the current time plus a second. The reason for this is so that the migrations for the engine are run after any existing migrations in the application. -To run these migrations within the context of the application, simply run `bin/rails +To run these migrations within the context of the application, simply run `rails db:migrate`. When accessing the engine through `http://localhost:3000/blog`, the articles will be empty. This is because the table created inside the application is different from the one created within the engine. Go ahead, play around with the @@ -734,14 +737,14 @@ If you would like to run migrations only from one engine, you can do it by specifying `SCOPE`: ```bash -bin/rails db:migrate SCOPE=blorgh +rails db:migrate SCOPE=blorgh ``` This may be useful if you want to revert engine's migrations before removing it. To revert all migrations from blorgh engine you can run code such as: ```bash -bin/rails db:migrate SCOPE=blorgh VERSION=0 +rails db:migrate SCOPE=blorgh VERSION=0 ``` ### Using a Class Provided by the Application @@ -768,7 +771,7 @@ application: rails g model user name:string ``` -The `bin/rails db:migrate` command needs to be run here to ensure that our +The `rails db:migrate` command needs to be run here to ensure that our application has the `users` table for future use. Also, to keep it simple, the articles form will have a new text field called @@ -828,7 +831,7 @@ of associating the records in the `blorgh_articles` table with the records in th To generate this new column, run this command within the engine: ```bash -$ bin/rails g migration add_author_id_to_blorgh_articles author_id:integer +$ rails g migration add_author_id_to_blorgh_articles author_id:integer ``` NOTE: Due to the migration's name and the column specification after it, Rails @@ -840,7 +843,7 @@ This migration will need to be run on the application. To do that, it must first be copied using this command: ```bash -$ bin/rails blorgh:install:migrations +$ rails blorgh:install:migrations ``` Notice that only _one_ migration was copied over here. This is because the first @@ -855,7 +858,7 @@ Copied migration [timestamp]_add_author_id_to_blorgh_articles.blorgh.rb from blo Run the migration using: ```bash -$ bin/rails db:migrate +$ rails db:migrate ``` Now with all the pieces in place, an action will take place that will associate @@ -998,7 +1001,7 @@ some sort of identifier by which it can be referenced. #### General Engine Configuration Within an engine, there may come a time where you wish to use things such as -initializers, internationalization or other configuration options. The great +initializers, internationalization, or other configuration options. The great news is that these things are entirely possible, because a Rails engine shares much the same functionality as a Rails application. In fact, a Rails application's functionality is actually a superset of what is provided by @@ -1020,11 +1023,11 @@ Testing an engine When an engine is generated, there is a smaller dummy application created inside it at `test/dummy`. This application is used as a mounting point for the engine, to make testing the engine extremely simple. You may extend this application by -generating controllers, models or views from within the directory, and then use +generating controllers, models, or views from within the directory, and then use those to test your engine. The `test` directory should be treated like a typical Rails testing environment, -allowing for unit, functional and integration tests. +allowing for unit, functional, and integration tests. ### Functional Tests @@ -1362,7 +1365,7 @@ need to require `admin.css` or `admin.js`. Only the gem's admin layout needs these assets. It doesn't make sense for the host app to include `"blorgh/admin.css"` in its stylesheets. In this situation, you should explicitly define these assets for precompilation. This tells Sprockets to add -your engine assets when `bin/rails assets:precompile` is triggered. +your engine assets when `rails assets:precompile` is triggered. You can define assets for precompilation in `engine.rb`: diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 53c567727f..a4f7e6f601 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Action View Form Helpers ======================== @@ -165,7 +165,7 @@ make it easier for users to click the inputs. Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, time fields, color fields, datetime-local fields, month fields, week fields, -URL fields, email fields, number fields and range fields: +URL fields, email fields, number fields, and range fields: ```erb <%= text_area_tag(:message, "Hi, nice site", size: "24x6") %> @@ -208,7 +208,7 @@ Output: Hidden inputs are not shown to the user but instead hold data like any textual input. Values inside them can be changed with JavaScript. IMPORTANT: The search, telephone, date, time, color, datetime, datetime-local, -month, week, URL, email, number and range inputs are HTML5 controls. +month, week, URL, email, number, and range inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely [no shortage of solutions for this](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills), although a popular tool at the moment is @@ -442,7 +442,7 @@ output: Whenever Rails sees that the internal value of an option being generated matches this value, it will add the `selected` attribute to that option. -WARNING: When `:include_blank` or `:prompt` are not present, `:include_blank` is forced true if the select attribute `required` is true, display `size` is one and `multiple` is not true. +WARNING: When `:include_blank` or `:prompt` are not present, `:include_blank` is forced true if the select attribute `required` is true, display `size` is one, and `multiple` is not true. You can add arbitrary attributes to the options using hashes: @@ -651,7 +651,7 @@ def upload end ``` -Once a file has been uploaded, there are a multitude of potential tasks, ranging from where to store the files (on disk, Amazon S3, etc) and associating them with models to resizing image files and generating thumbnails. The intricacies of this are beyond the scope of this guide, but there are several libraries designed to assist with these. Two of the better known ones are [CarrierWave](https://github.com/jnicklas/carrierwave) and [Paperclip](https://github.com/thoughtbot/paperclip). +Once a file has been uploaded, there are a multitude of potential tasks, ranging from where to store the files (on disk, Amazon S3, etc) and associating them with models to resizing image files and generating thumbnails. [Active Storage](https://guides.rubyonrails.org/active_storage_overview.html) is designed to assist with these tasks. NOTE: If the user has not selected a file the corresponding parameter will be an empty string. @@ -709,7 +709,7 @@ Understanding Parameter Naming Conventions ------------------------------------------ As you've seen in the previous sections, values from forms can be at the top level of the `params` hash or nested in another hash. For example, in a standard `create` -action for a Person model, `params[:person]` would usually be a hash of all the attributes for the person to create. The `params` hash can also contain arrays, arrays of hashes and so on. +action for a Person model, `params[:person]` would usually be a hash of all the attributes for the person to create. The `params` hash can also contain arrays, arrays of hashes, and so on. Fundamentally HTML forms don't know about any sort of structured data, all they generate is name-value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses. @@ -763,7 +763,7 @@ We can mix and match these two concepts. One element of a hash might be an array This would result in `params[:addresses]` being an array of hashes with keys `line1`, `line2` and `city`. Rails decides to start accumulating values in a new hash whenever it encounters an input name that already exists in the current hash. -There's a restriction, however, while hashes can be nested arbitrarily, only one level of "arrayness" is allowed. Arrays can usually be replaced by hashes; for example, instead of having an array of model objects, one can have a hash of model objects keyed by their id, an array index or some other parameter. +There's a restriction, however, while hashes can be nested arbitrarily, only one level of "arrayness" is allowed. Arrays can usually be replaced by hashes; for example, instead of having an array of model objects, one can have a hash of model objects keyed by their id, an array index, or some other parameter. WARNING: Array parameters do not play well with the `check_box` helper. According to the HTML specification unchecked checkboxes submit no value. However it is often convenient for a checkbox to always submit a value. The `check_box` helper fakes this by creating an auxiliary hidden input with the same name. If the checkbox is unchecked only the hidden input is submitted and if it is checked then both are submitted but the value submitted by the checkbox takes precedence. When working with array parameters this duplicate submission will confuse Rails since duplicate input names are how it decides when to start a new array element. It is preferable to either use `check_box_tag` or to use hashes instead of arrays. @@ -823,7 +823,7 @@ will create inputs like <input id="person_address_primary_1_city" name="person[address][primary][1][city]" type="text" value="bologna" /> ``` -As a general rule the final input name is the concatenation of the name given to `fields_for`/`form_for`, the index value and the name of the attribute. You can also pass an `:index` option directly to helpers such as `text_field`, but it is usually less repetitive to specify this at the form builder level rather than on individual input controls. +As a general rule the final input name is the concatenation of the name given to `fields_for`/`form_for`, the index value, and the name of the attribute. You can also pass an `:index` option directly to helpers such as `text_field`, but it is usually less repetitive to specify this at the form builder level rather than on individual input controls. As a shortcut you can append [] to the name and omit the `:index` option. This is the same as specifying `index: address` so @@ -873,7 +873,7 @@ Or if you don't want to render an `authenticity_token` field: Building Complex Forms ---------------------- -Many apps grow beyond simple forms editing a single object. For example, when creating a `Person` you might want to allow the user to (on the same form) create multiple address records (home, work, etc.). When later editing that person the user should be able to add, remove or amend addresses as necessary. +Many apps grow beyond simple forms editing a single object. For example, when creating a `Person` you might want to allow the user to (on the same form) create multiple address records (home, work, etc.). When later editing that person the user should be able to add, remove, or amend addresses as necessary. ### Configuring the Model @@ -890,7 +890,7 @@ class Address < ApplicationRecord end ``` -This creates an `addresses_attributes=` method on `Person` that allows you to create, update and (optionally) destroy addresses. +This creates an `addresses_attributes=` method on `Person` that allows you to create, update, and (optionally) destroy addresses. ### Nested Forms diff --git a/guides/source/generators.md b/guides/source/generators.md index b7b8262e4a..89424a161b 100644 --- a/guides/source/generators.md +++ b/guides/source/generators.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Creating and Customizing Rails Generators & Templates ===================================================== @@ -26,13 +26,13 @@ When you create an application using the `rails` command, you are in fact using ```bash $ rails new myapp $ cd myapp -$ bin/rails generate +$ rails generate ``` You will get a list of all generators that comes with Rails. If you need a detailed description of the helper generator, for example, you can simply do: ```bash -$ bin/rails generate helper --help +$ rails generate helper --help ``` Creating Your First Generator @@ -57,13 +57,13 @@ Our new generator is quite simple: it inherits from `Rails::Generators::Base` an To invoke our new generator, we just need to do: ```bash -$ bin/rails generate initializer +$ rails generate initializer ``` Before we go on, let's see our brand new generator description: ```bash -$ bin/rails generate initializer --help +$ rails generate initializer --help ``` Rails is usually able to generate good descriptions if a generator is namespaced, as `ActiveRecord::Generators::ModelGenerator`, but not in this particular case. We can solve this problem in two ways. The first one is calling `desc` inside our generator: @@ -85,7 +85,7 @@ Creating Generators with Generators Generators themselves have a generator: ```bash -$ bin/rails generate generator initializer +$ rails generate generator initializer create lib/generators/initializer create lib/generators/initializer/initializer_generator.rb create lib/generators/initializer/USAGE @@ -107,7 +107,7 @@ First, notice that we are inheriting from `Rails::Generators::NamedBase` instead We can see that by invoking the description of this new generator (don't forget to delete the old generator file): ```bash -$ bin/rails generate initializer --help +$ rails generate initializer --help Usage: rails generate initializer NAME [options] ``` @@ -135,7 +135,7 @@ end And let's execute our generator: ```bash -$ bin/rails generate initializer core_extensions +$ rails generate initializer core_extensions ``` We can see that now an initializer named core_extensions was created at `config/initializers/core_extensions.rb` with the contents of our template. That means that `copy_file` copied a file in our source root to the destination path we gave. The method `file_name` is automatically created when we inherit from `Rails::Generators::NamedBase`. @@ -174,7 +174,7 @@ end Before we customize our workflow, let's first see what our scaffold looks like: ```bash -$ bin/rails generate scaffold User name:string +$ rails generate scaffold User name:string invoke active_record create db/migrate/20130924151154_create_users.rb create app/models/user.rb @@ -221,7 +221,7 @@ If we want to avoid generating the default `app/assets/stylesheets/scaffolds.scs end ``` -The next customization on the workflow will be to stop generating stylesheet, JavaScript and test fixture files for scaffolds altogether. We can achieve that by changing our configuration to the following: +The next customization on the workflow will be to stop generating stylesheet, JavaScript, and test fixture files for scaffolds altogether. We can achieve that by changing our configuration to the following: ```ruby config.generators do |g| @@ -233,12 +233,12 @@ config.generators do |g| end ``` -If we generate another resource with the scaffold generator, we can see that stylesheet, JavaScript and fixture files are not created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators. +If we generate another resource with the scaffold generator, we can see that stylesheet, JavaScript, and fixture files are not created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators. To demonstrate this, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator within the rails namespace, as this is where rails searches for generators used as hooks: ```bash -$ bin/rails generate generator rails/my_helper +$ rails generate generator rails/my_helper create lib/generators/rails/my_helper create lib/generators/rails/my_helper/my_helper_generator.rb create lib/generators/rails/my_helper/USAGE @@ -267,7 +267,7 @@ end We can try out our new generator by creating a helper for products: ```bash -$ bin/rails generate my_helper products +$ rails generate my_helper products create app/helpers/products_helper.rb ``` @@ -295,7 +295,7 @@ end and see it in action when invoking the generator: ```bash -$ bin/rails generate scaffold Article body:text +$ rails generate scaffold Article body:text [...] invoke my_helper create app/helpers/articles_helper.rb @@ -397,7 +397,7 @@ end Now, if you create a Comment scaffold, you will see that the shoulda generators are being invoked, and at the end, they are just falling back to TestUnit generators: ```bash -$ bin/rails generate scaffold Comment body:text +$ rails generate scaffold Comment body:text invoke active_record create db/migrate/20130924143118_create_comments.rb create app/models/comment.rb diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 5b6cfe6659..88a13cdd70 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Getting Started with Rails ========================== @@ -93,11 +93,9 @@ ruby 2.5.0 Rails requires Ruby version 2.4.1 or later. If the version number returned is less than that number, you'll need to install a fresh copy of Ruby. -TIP: A number of tools exist to help you quickly install Ruby and Ruby -on Rails on your system. Windows users can use [Rails Installer](http://railsinstaller.org), -while macOS users can use [Tokaido](https://github.com/tokaido/tokaidoapp). -For more installation methods for most Operating Systems take a look at -[ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/). +TIP: To quickly install Ruby and Ruby on Rails on your system in Windows, you can use +[Rails Installer](http://railsinstaller.org). For more installation methods for most +Operating Systems take a look at [ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/). If you are working on Windows, you should also install the [Ruby Installer Development Kit](https://rubyinstaller.org/downloads/). @@ -169,7 +167,7 @@ of the files and folders that Rails created by default: | File/Folder | Purpose | | ----------- | ------- | -|app/|Contains the controllers, models, views, helpers, mailers, channels, jobs and assets for your application. You'll focus on this folder for the remainder of this guide.| +|app/|Contains the controllers, models, views, helpers, mailers, channels, jobs, and assets for your application. You'll focus on this folder for the remainder of this guide.| |bin/|Contains the rails script that starts your app and can contain other scripts you use to setup, update, deploy, or run your application.| |config/|Configure your application's routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html).| |config.ru|Rack configuration for Rack based servers used to start the application. For more information about Rack, see the [Rack website](https://rack.github.io/).| @@ -181,6 +179,7 @@ of the files and folders that Rails created by default: |public/|The only folder seen by the world as-is. Contains static files and compiled assets.| |Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing `Rakefile`, you should add your own tasks by adding files to the `lib/tasks` directory of your application.| |README.md|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.| +|storage/|Active Storage files for Disk Service. This is covered in [Active Storage Overview](active_storage_overview.html).| |test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html).| |tmp/|Temporary files (like cache and pid files).| |vendor/|A place for all third-party code. In a typical Rails application this includes vendored gems.| @@ -200,7 +199,7 @@ start a web server on your development machine. You can do this by running the following in the `blog` directory: ```bash -$ bin/rails server +$ rails server ``` TIP: If you are using Windows, you have to pass the scripts under the `bin` @@ -256,7 +255,7 @@ tell it you want a controller called "Welcome" with an action called "index", just like this: ```bash -$ bin/rails generate controller Welcome index +$ rails generate controller Welcome index ``` Rails will create several files and a route for you. @@ -306,7 +305,7 @@ Open the file `config/routes.rb` in your editor. Rails.application.routes.draw do get 'welcome/index' - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end ``` @@ -329,9 +328,9 @@ end application to the welcome controller's index action and `get 'welcome/index'` tells Rails to map requests to <http://localhost:3000/welcome/index> to the welcome controller's index action. This was created earlier when you ran the -controller generator (`bin/rails generate controller Welcome index`). +controller generator (`rails generate controller Welcome index`). -Launch the web server again if you stopped it to generate the controller (`bin/rails +Launch the web server again if you stopped it to generate the controller (`rails server`) and navigate to <http://localhost:3000> in your browser. You'll see the "Hello, Rails!" message you put into `app/views/welcome/index.html.erb`, indicating that this new route is indeed going to `WelcomeController`'s `index` @@ -342,7 +341,7 @@ TIP: For more information about routing, refer to [Rails Routing from the Outsid Getting Up and Running ---------------------- -Now that you've seen how to create a controller, an action and a view, let's +Now that you've seen how to create a controller, an action, and a view, let's create something with a bit more substance. In the Blog application, you will now create a new _resource_. A resource is the @@ -365,13 +364,13 @@ Rails.application.routes.draw do end ``` -If you run `bin/rails routes`, you'll see that it has defined routes for all the +If you run `rails routes`, you'll see that it has defined routes for all the standard RESTful actions. The meaning of the prefix column (and other columns) will be seen later, but for now notice that Rails has inferred the singular form `article` and makes meaningful use of the distinction. ```bash -$ bin/rails routes +$ rails routes Prefix Verb URI Pattern Controller#Action welcome_index GET /welcome/index(.:format) welcome#index articles GET /articles(.:format) articles#index @@ -410,7 +409,7 @@ a controller called `ArticlesController`. You can do this by running this command: ```bash -$ bin/rails generate controller Articles +$ rails generate controller Articles ``` If you open up the newly generated `app/controllers/articles_controller.rb` @@ -562,10 +561,10 @@ this: In this example, the `articles_path` helper is passed to the `:url` option. To see what Rails will do with this, we look back at the output of -`bin/rails routes`: +`rails routes`: ```bash -$ bin/rails routes +$ rails routes Prefix Verb URI Pattern Controller#Action welcome_index GET /welcome/index(.:format) welcome#index articles GET /articles(.:format) articles#index @@ -659,7 +658,7 @@ Rails developers tend to use when creating new models. To create the new model, run this command in your terminal: ```bash -$ bin/rails generate model Article title:string text:text +$ rails generate model Article title:string text:text ``` With that command we told Rails that we want an `Article` model, together @@ -678,7 +677,7 @@ models, as that will be done automatically by Active Record. ### Running a Migration -As we've just seen, `bin/rails generate model` created a _database migration_ file +As we've just seen, `rails generate model` created a _database migration_ file inside the `db/migrate` directory. Migrations are Ruby classes that are designed to make it simple to create and modify database tables. Rails uses rake commands to run migrations, and it's possible to undo a migration after @@ -711,10 +710,10 @@ two timestamp fields to allow Rails to track article creation and update times. TIP: For more information about migrations, refer to [Active Record Migrations] (active_record_migrations.html). -At this point, you can use a bin/rails command to run the migration: +At this point, you can use a rails command to run the migration: ```bash -$ bin/rails db:migrate +$ rails db:migrate ``` Rails will execute this migration command and tell you it created the Articles @@ -731,7 +730,7 @@ NOTE. Because you're working in the development environment by default, this command will apply to the database defined in the `development` section of your `config/database.yml` file. If you would like to execute migrations in another environment, for instance in production, you must explicitly pass it when -invoking the command: `bin/rails db:migrate RAILS_ENV=production`. +invoking the command: `rails db:migrate RAILS_ENV=production`. ### Saving data in the controller @@ -810,7 +809,7 @@ private TIP: For more information, refer to the reference above and [this blog article about Strong Parameters] -(http://weblog.rubyonrails.org/2012/3/21/strong-parameters/). +(https://weblog.rubyonrails.org/2012/3/21/strong-parameters/). ### Showing Articles @@ -818,7 +817,7 @@ If you submit the form again now, Rails will complain about not finding the `show` action. That's not very useful though, so let's add the `show` action before proceeding. -As we have seen in the output of `bin/rails routes`, the route for `show` action is +As we have seen in the output of `rails routes`, the route for `show` action is as follows: ``` @@ -880,7 +879,7 @@ Visit <http://localhost:3000/articles/new> and give it a try! ### Listing all articles We still need a way to list all our articles, so let's do that. -The route for this as per output of `bin/rails routes` is: +The route for this as per output of `rails routes` is: ``` articles GET /articles(.:format) articles#index @@ -1204,14 +1203,15 @@ it look as follows: This time we point the form to the `update` action, which is not defined yet but will be very soon. -Passing the article object to the method will automatically set the URL for +Passing the article object to the `form_with` method will automatically set the URL for submitting the edited article form. This option tells Rails that we want this form to be submitted via the `PATCH` HTTP method, which is the HTTP method you're expected to use to **update** resources according to the REST protocol. -The arguments to `form_with` could be model objects, say, `model: @article` which would -cause the helper to fill in the form with the fields of the object. Passing in a -symbol scope (`scope: :article`) just creates the fields but without anything filled into them. +Also, passing a model object to `form_with`, like `model: @article` in the edit +view above, will cause form helpers to fill in form fields with the corresponding +values of the object. Passing in a symbol scope such as `scope: :article`, as +was done in the new view, only creates empty form fields. More details can be found in [form_with documentation] (http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with). @@ -1376,7 +1376,7 @@ Then do the same for the `app/views/articles/edit.html.erb` view: We're now ready to cover the "D" part of CRUD, deleting articles from the database. Following the REST convention, the route for -deleting articles as per output of `bin/rails routes` is: +deleting articles as per output of `rails routes` is: ```ruby DELETE /articles/:id(.:format) articles#destroy @@ -1526,7 +1526,7 @@ the `Article` model. This time we'll create a `Comment` model to hold a reference to an article. Run this command in your terminal: ```bash -$ bin/rails generate model Comment commenter:string body:text article:references +$ rails generate model Comment commenter:string body:text article:references ``` This command will generate four files: @@ -1577,7 +1577,7 @@ for it, and a foreign key constraint that points to the `id` column of the `arti table. Go ahead and run the migration: ```bash -$ bin/rails db:migrate +$ rails db:migrate ``` Rails is smart enough to only execute the migrations that have not already been @@ -1653,7 +1653,7 @@ With the model in hand, you can turn your attention to creating a matching controller. Again, we'll use the same generator we used before: ```bash -$ bin/rails generate controller Comments +$ rails generate controller Comments ``` This creates five files and one empty directory: diff --git a/guides/source/i18n.md b/guides/source/i18n.md index 339b356a78..7843df5b18 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Rails Internationalization (I18n) API ===================================== @@ -11,7 +11,7 @@ So, in the process of _internationalizing_ your Rails application you have to: * Ensure you have support for i18n. * Tell Rails where to find locale dictionaries. -* Tell Rails how to set, preserve and switch locales. +* Tell Rails how to set, preserve, and switch locales. In the process of _localizing_ your application you'll probably want to do the following three things: @@ -107,7 +107,7 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor The I18n library will use **English** as a **default locale**, i.e. if a different locale is not set, `:en` will be used for looking up translations. -NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](https://groups.google.com/forum/#!topic/rails-i18n/FN7eLH2-lHA)), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. +NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](https://groups.google.com/forum/#!topic/rails-i18n/FN7eLH2-lHA)), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th`, or `:es` (for Czech, Thai, and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. The **translations load path** (`I18n.load_path`) is an array of paths to files that will be loaded automatically. Configuring this path allows for customization of translations directory structure and file naming scheme. @@ -596,7 +596,7 @@ Covered are features like these: ### Looking up Translations -#### Basic Lookup, Scopes and Nested Keys +#### Basic Lookup, Scopes, and Nested Keys Translations are looked up by keys which can be both Symbols or Strings, so these calls are equivalent: @@ -829,14 +829,14 @@ For example when you add the following translations: en: activerecord: models: - user: Dude + user: Customer attributes: user: login: "Handle" # will translate User attribute "login" as "Handle" ``` -Then `User.model_name.human` will return "Dude" and `User.human_attribute_name("login")` will return "Handle". +Then `User.model_name.human` will return "Customer" and `User.human_attribute_name("login")` will return "Handle". You can also set a plural form for model names, adding as following: @@ -845,11 +845,11 @@ en: activerecord: models: user: - one: Dude - other: Dudes + one: Customer + other: Customers ``` -Then `User.model_name.human(count: 2)` will return "Dudes". With `count: 1` or without params will return "Dude". +Then `User.model_name.human(count: 2)` will return "Customers". With `count: 1` or without params will return "Customer". In the event you need to access nested attributes within a given model, you should nest these under `model/attribute` at the model level of your translation file: @@ -857,12 +857,12 @@ In the event you need to access nested attributes within a given model, you shou en: activerecord: attributes: - user/gender: - female: "Female" - male: "Male" + user/role: + admin: "Admin" + contributor: "Contributor" ``` -Then `User.human_attribute_name("gender.female")` will return "Female". +Then `User.human_attribute_name("role.admin")` will return "Admin". NOTE: If you are using a class which includes `ActiveModel` and does not inherit from `ActiveRecord::Base`, replace `activerecord` with `activemodel` in the above key paths. @@ -1190,7 +1190,7 @@ I18n support in Ruby on Rails was introduced in the release 2.2 and is still evo Thus we encourage everybody to experiment with new ideas and features in gems or other libraries and make them available to the community. (Don't forget to announce your work on our [mailing list](https://groups.google.com/forum/#!forum/rails-i18n)!) -If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data and send a [pull request](https://help.github.com/articles/about-pull-requests/). +If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data, and send a [pull request](https://help.github.com/articles/about-pull-requests/). Resources diff --git a/guides/source/index.html.erb b/guides/source/index.html.erb index 2fdf18a2e9..76f01fea0a 100644 --- a/guides/source/index.html.erb +++ b/guides/source/index.html.erb @@ -10,7 +10,9 @@ Ruby on Rails Guides <div id="subCol"> <dl> <dt></dt> - <dd class="kindle">Rails Guides are also available for <%= link_to 'Kindle', @mobi %>.</dd> + <% unless @edge -%> + <dd class="kindle">Rails Guides are also available for <%= link_to 'Kindle', @mobi %>.</dd> + <% end -%> <dd class="work-in-progress">Guides marked with this icon are currently being worked on and will not be available in the Guides Index menu. While still useful, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections.</dd> </dl> </div> diff --git a/guides/source/initialization.md b/guides/source/initialization.md index d3b122c7fe..c41eae18cf 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** The Rails Initialization Process ================================ @@ -45,7 +45,7 @@ load Gem.bin_path('railties', 'rails', version) ``` If you try out this command in a Rails console, you would see that this loads -`railties/exe/rails`. A part of the file `railties/exe/rails.rb` has the +`railties/exe/rails`. A part of the file `railties/exe/rails` has the following code: ```ruby diff --git a/guides/source/kindle/rails_guides.opf.erb b/guides/source/kindle/rails_guides.opf.erb index 63eeb007d7..1882ec1005 100644 --- a/guides/source/kindle/rails_guides.opf.erb +++ b/guides/source/kindle/rails_guides.opf.erb @@ -26,7 +26,7 @@ <item id="<%= document['url'] %>" media-type="text/html" href="<%= document['url'] %>" /> <% end %> - <% %w{toc.html credits.html welcome.html copyright.html}.each do |url| %> + <% %w{toc.html welcome.html copyright.html}.each do |url| %> <item id="<%= url %>" media-type="text/html" href="<%= url %>" /> <% end %> @@ -38,7 +38,6 @@ <spine toc="toc"> <itemref idref="toc.html" /> <itemref idref="welcome.html" /> - <itemref idref="credits.html" /> <itemref idref="copyright.html" /> <% documents_flat.each do |document| %> <itemref idref="<%= document['url'] %>" /> diff --git a/guides/source/kindle/toc.html.erb b/guides/source/kindle/toc.html.erb index 0f4228ed6b..b77ac2e99d 100644 --- a/guides/source/kindle/toc.html.erb +++ b/guides/source/kindle/toc.html.erb @@ -18,7 +18,6 @@ Ruby on Rails Guides <% end %> <hr /> <ul> - <li><a href="credits.html">Credits</a></li> <li><a href="copyright.html">Copyright & License</a></li> </ul> </div> diff --git a/guides/source/kindle/toc.ncx.erb b/guides/source/kindle/toc.ncx.erb index 5094fea4ca..9b73bc9bea 100644 --- a/guides/source/kindle/toc.ncx.erb +++ b/guides/source/kindle/toc.ncx.erb @@ -30,10 +30,6 @@ </navLabel> <content src="welcome.html"/> </navPoint> - <navPoint class="article" id="credits" playOrder="3"> - <navLabel><text>Credits</text></navLabel> - <content src="credits.html"/> - </navPoint> <navPoint class="article" id="copyright" playOrder="4"> <navLabel><text>Copyright & License</text></navLabel> <content src="copyright.html"/> diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb index 3981199e95..e8a1bd4f3d 100644 --- a/guides/source/layout.html.erb +++ b/guides/source/layout.html.erb @@ -29,8 +29,8 @@ More Ruby on Rails </span> <ul class="more-info-links s-hidden"> - <li class="more-info"><a href="http://weblog.rubyonrails.org/">Blog</a></li> - <li class="more-info"><a href="http://guides.rubyonrails.org/">Guides</a></li> + <li class="more-info"><a href="https://weblog.rubyonrails.org/">Blog</a></li> + <li class="more-info"><a href="https://guides.rubyonrails.org/">Guides</a></li> <li class="more-info"><a href="http://api.rubyonrails.org/">API</a></li> <li class="more-info"><a href="https://stackoverflow.com/questions/tagged/ruby-on-rails">Ask for help</a></li> <li class="more-info"><a href="https://github.com/rails/rails">Contribute on GitHub</a></li> @@ -59,7 +59,6 @@ </div> </li> <li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribute</a></li> - <li><a class="nav-item" href="credits.html">Credits</a></li> <li class="guides-index guides-index-small"> <select class="guides-index-item nav-item"> <option value="index.html">Guides Index</option> @@ -124,15 +123,8 @@ </div> </div> - <script type="text/javascript" src="javascripts/jquery.min.js"></script> - <script type="text/javascript" src="javascripts/responsive-tables.js"></script> - <script type="text/javascript" src="javascripts/guides.js"></script> <script type="text/javascript" src="javascripts/syntaxhighlighter.js"></script> - <script type="text/javascript"> - syntaxhighlighterConfig = { - autoLinks: false, - }; - $(guidesIndex.bind); - </script> + <script type="text/javascript" src="javascripts/guides.js"></script> + <script type="text/javascript" src="javascripts/responsive-tables.js"></script> </body> </html> diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 15345c94b7..00da65b784 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Layouts and Rendering in Rails ============================== @@ -170,7 +170,7 @@ render a file, because Windows filenames do not have the same format as Unix fil #### Wrapping it up -The above three ways of rendering (rendering another template within the controller, rendering a template within another controller and rendering an arbitrary file on the file system) are actually variants of the same action. +The above three ways of rendering (rendering another template within the controller, rendering a template within another controller, and rendering an arbitrary file on the file system) are actually variants of the same action. In fact, in the BooksController class, inside of the update action where we want to render the edit template if the book does not update successfully, all of the following render calls would all render the `edit.html.erb` template in the `views/books` directory: @@ -403,7 +403,7 @@ Rails understands both numeric status codes and the corresponding symbols shown | | 511 | :network_authentication_required | NOTE: If you try to render content along with a non-content status code -(100-199, 204, 205 or 304), it will be dropped from the response. +(100-199, 204, 205, or 304), it will be dropped from the response. ##### The `:formats` Option @@ -1210,7 +1210,7 @@ Partials are very useful in rendering collections. When you pass a collection to When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is `_product`, and within the `_product` partial, you can refer to `product` to get the instance that is being rendered. -There is also a shorthand for this. Assuming `@products` is a collection of `product` instances, you can simply write this in the `index.html.erb` to produce the same result: +There is also a shorthand for this. Assuming `@products` is a collection of `Product` instances, you can simply write this in the `index.html.erb` to produce the same result: ```html+erb <h1>Products</h1> diff --git a/guides/source/maintenance_policy.md b/guides/source/maintenance_policy.md index 1d6a4edb5b..b14b7a2c90 100644 --- a/guides/source/maintenance_policy.md +++ b/guides/source/maintenance_policy.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Maintenance Policy for Ruby on Rails ==================================== @@ -44,7 +44,7 @@ from. In special situations, where someone from the Core Team agrees to support more series, they are included in the list of supported series. -**Currently included series:** `5.1.Z`. +**Currently included series:** `5.2.Z`. Security Issues --------------- @@ -59,16 +59,16 @@ be built from 1.2.2, and then added to the end of 1-2-stable. This means that security releases are easy to upgrade to if you're running the latest version of Rails. -**Currently included series:** `5.1.Z`, `5.0.Z`. +**Currently included series:** `5.2.Z`, `5.1.Z`. Severe Security Issues ---------------------- -For severe security issues we will provide new versions as above, and also the +For severe security issues all releases in the current major series, and also the last major release series will receive patches and new versions. The classification of the security issue is judged by the core team. -**Currently included series:** `5.1.Z`, `5.0.Z`, `4.2.Z`. +**Currently included series:** `5.2.Z`, `5.1.Z`, `5.0.Z`, `4.2.Z`. Unsupported Release Series -------------------------- diff --git a/guides/source/plugins.md b/guides/source/plugins.md index 15073af6be..7c9784dfe3 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** The Basics of Creating Rails Plugins ==================================== @@ -135,10 +135,10 @@ To test that your method does what it says it does, run the unit tests with `bin 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips ``` -To see this in action, change to the `test/dummy` directory, fire up a console and start squawking: +To see this in action, change to the `test/dummy` directory, fire up a console, and start squawking: ```bash -$ bin/rails console +$ rails console >> "Hello World".to_squawk => "squawk! Hello World" ``` @@ -241,8 +241,8 @@ We can easily generate these models in our "dummy" Rails application by running ```bash $ cd test/dummy -$ bin/rails generate model Hickwall last_squawk:string -$ bin/rails generate model Wickwall last_squawk:string last_tweet:string +$ rails generate model Hickwall last_squawk:string +$ rails generate model Wickwall last_squawk:string last_tweet:string ``` Now you can create the necessary database tables in your testing database by navigating to your dummy app @@ -250,7 +250,7 @@ and migrating the database. First, run: ```bash $ cd test/dummy -$ bin/rails db:migrate +$ rails db:migrate ``` While you are here, change the Hickwall and Wickwall models so that they know that they are supposed to act @@ -455,7 +455,7 @@ gem "yaffle", git: "https://github.com/rails/yaffle.git" After running `bundle install`, your gem functionality will be available to the application. When the gem is ready to be shared as a formal release, it can be published to [RubyGems](https://rubygems.org). -For more information about publishing gems to RubyGems, see: [Publishing your gem](http://guides.rubygems.org/publishing). +For more information about publishing gems to RubyGems, see: [Publishing your gem](https://guides.rubygems.org/publishing). RDoc Documentation ------------------ @@ -481,4 +481,4 @@ $ bundle exec rake rdoc * [Developing a RubyGem using Bundler](https://github.com/radar/guides/blob/master/gem-development.md) * [Using .gemspecs as Intended](http://yehudakatz.com/2010/04/02/using-gemspecs-as-intended/) -* [Gemspec Reference](http://guides.rubygems.org/specification-reference/) +* [Gemspec Reference](https://guides.rubygems.org/specification-reference/) diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index e087834a2f..bc68a555c5 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Rails Application Templates =========================== @@ -22,11 +22,11 @@ $ rails new blog -m ~/template.rb $ rails new blog -m http://example.com/template.rb ``` -You can use the `app:template` Rake task to apply templates to an existing Rails application. The location of the template needs to be passed in via the LOCATION environment variable. Again, this can either be path to a file or a URL. +You can use the `app:template` rails command to apply templates to an existing Rails application. The location of the template needs to be passed in via the LOCATION environment variable. Again, this can either be path to a file or a URL. ```bash -$ bin/rails app:template LOCATION=~/template.rb -$ bin/rails app:template LOCATION=http://example.com/template.rb +$ rails app:template LOCATION=~/template.rb +$ rails app:template LOCATION=http://example.com/template.rb ``` Template API @@ -177,19 +177,19 @@ run "rm README.rdoc" ### rails_command(command, options = {}) -Runs the supplied task in the Rails application. Let's say you want to migrate the database: +Runs the supplied command in the Rails application. Let's say you want to migrate the database: ```ruby rails_command "db:migrate" ``` -You can also run tasks with a different Rails environment: +You can also run commands with a different Rails environment: ```ruby rails_command "db:migrate", env: 'production' ``` -You can also run tasks as a super-user: +You can also run commands as a super-user: ```ruby rails_command "log:clear", sudo: true diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index 1627205b7b..c33851a0f9 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Rails on Rack ============= @@ -13,12 +13,12 @@ After reading this guide, you will know: -------------------------------------------------------------------------------- -WARNING: This guide assumes a working knowledge of Rack protocol and Rack concepts such as middlewares, url maps and `Rack::Builder`. +WARNING: This guide assumes a working knowledge of Rack protocol and Rack concepts such as middlewares, url maps, and `Rack::Builder`. Introduction to Rack -------------------- -Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call. +Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call. Explaining how Rack works is not really in the scope of this guide. In case you are not familiar with Rack's basics, you should check out the [Resources](#resources) @@ -94,10 +94,10 @@ but is built for better flexibility and more features to meet Rails' requirement ### Inspecting Middleware Stack -Rails has a handy task for inspecting the middleware stack in use: +Rails has a handy command for inspecting the middleware stack in use: ```bash -$ bin/rails middleware +$ rails middleware ``` For a freshly generated Rails application, this might produce something like: @@ -134,7 +134,7 @@ The default middlewares shown here (and some others) are each summarized in the ### Configuring Middleware Stack -Rails provides a simple configuration interface `config.middleware` for adding, removing and modifying the middlewares in the middleware stack via `application.rb` or the environment specific configuration file `environments/<environment>.rb`. +Rails provides a simple configuration interface `config.middleware` for adding, removing, and modifying the middlewares in the middleware stack via `application.rb` or the environment specific configuration file `environments/<environment>.rb`. #### Adding a Middleware @@ -181,7 +181,7 @@ And now if you inspect the middleware stack, you'll find that `Rack::Runtime` is not a part of it. ```bash -$ bin/rails middleware +$ rails middleware (in /Users/lifo/Rails/blog) use ActionDispatch::Static use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8> diff --git a/guides/source/routing.md b/guides/source/routing.md index 3cf5b56340..8c69e2600b 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Rails Routing from the Outside In ================================= @@ -36,6 +36,8 @@ get '/patients/:id', to: 'patients#show' the request is dispatched to the `patients` controller's `show` action with `{ id: '17' }` in `params`. +NOTE: Rails uses snake_case for controller names here, if you have a multiple word controller like `MonsterTrucksController`, you want to use `monster_trucks#show` for example. + ### Generating Paths and URLs from Code You can also generate paths and URLs. If the route above is modified to be: @@ -136,7 +138,7 @@ Creating a resourceful route will also expose a number of helpers to the control * `edit_photo_path(:id)` returns `/photos/:id/edit` (for instance, `edit_photo_path(10)` returns `/photos/10/edit`) * `photo_path(:id)` returns `/photos/:id` (for instance, `photo_path(10)` returns `/photos/10`) -Each of these helpers has a corresponding `_url` helper (such as `photos_url`) which returns the same path prefixed with the current host, port and path prefix. +Each of these helpers has a corresponding `_url` helper (such as `photos_url`) which returns the same path prefixed with the current host, port, and path prefix. ### Defining Multiple Resources at the Same Time @@ -194,7 +196,7 @@ A singular resourceful route generates these helpers: * `edit_geocoder_path` returns `/geocoder/edit` * `geocoder_path` returns `/geocoder` -As with plural resources, the same helpers ending in `_url` will also include the host, port and path prefix. +As with plural resources, the same helpers ending in `_url` will also include the host, port, and path prefix. ### Controller Namespaces and Routing @@ -504,7 +506,7 @@ resources :photos do end ``` -This will recognize `/photos/1/preview` with GET, and route to the `preview` action of `PhotosController`, with the resource id value passed in `params[:id]`. It will also create the `photo_preview_url` and `photo_preview_path` helpers. +This will recognize `/photos/1/preview` with GET, and route to the `preview` action of `PhotosController`, with the resource id value passed in `params[:id]`. It will also create the `preview_photo_url` and `preview_photo_path` helpers. Within the block of member routes, each route name specifies the HTTP verb will be recognized. You can use `get`, `patch`, `put`, `post`, or `delete` here @@ -642,7 +644,7 @@ You can also use this to override routing methods defined by resources, like thi get ':username', to: 'users#show', as: :user ``` -This will define a `user_path` method that will be available in controllers, helpers and views that will go to a route such as `/bob`. Inside the `show` action of `UsersController`, `params[:username]` will contain the username for the user. Change `:username` in the route definition if you do not want your parameter name to be `:username`. +This will define a `user_path` method that will be available in controllers, helpers, and views that will go to a route such as `/bob`. Inside the `show` action of `UsersController`, `params[:username]` will contain the username for the user. Change `:username` in the route definition if you do not want your parameter name to be `:username`. ### HTTP Verb Constraints @@ -1059,7 +1061,7 @@ scope ':username' do end ``` -This will provide you with URLs such as `/bob/articles/1` and will allow you to reference the `username` part of the path as `params[:username]` in controllers, helpers and views. +This will provide you with URLs such as `/bob/articles/1` and will allow you to reference the `username` part of the path as `params[:username]` in controllers, helpers, and views. ### Restricting the Routes Created @@ -1137,10 +1139,10 @@ resources :videos, param: :identifier ``` ``` - videos GET /videos(.:format) videos#index - POST /videos(.:format) videos#create - new_videos GET /videos/new(.:format) videos#new -edit_videos GET /videos/:identifier/edit(.:format) videos#edit + videos GET /videos(.:format) videos#index + POST /videos(.:format) videos#create + new_video GET /videos/new(.:format) videos#new +edit_video GET /videos/:identifier/edit(.:format) videos#edit ``` ```ruby @@ -1158,7 +1160,7 @@ class Video < ApplicationRecord end video = Video.find_by(identifier: "Roman-Holiday") -edit_videos_path(video) # => "/videos/Roman-Holiday" +edit_video_path(video) # => "/videos/Roman-Holiday/edit" ``` Inspecting and Testing Routes @@ -1189,18 +1191,18 @@ edit_user GET /users/:id/edit(.:format) users#edit You can search through your routes with the grep option: -g. This outputs any routes that partially match the URL helper method name, the HTTP verb, or the URL path. ``` -$ bin/rails routes -g new_comment -$ bin/rails routes -g POST -$ bin/rails routes -g admin +$ rails routes -g new_comment +$ rails routes -g POST +$ rails routes -g admin ``` If you only want to see the routes that map to a specific controller, there's the -c option. ``` -$ bin/rails routes -c users -$ bin/rails routes -c admin/users -$ bin/rails routes -c Comments -$ bin/rails routes -c Articles::CommentsController +$ rails routes -c users +$ rails routes -c admin/users +$ rails routes -c Comments +$ rails routes -c Articles::CommentsController ``` TIP: You'll find that the output from `rails routes` is much more readable if you widen your terminal window until the output lines don't wrap. You can also use --expanded option to turn on the expanded table formatting mode. diff --git a/guides/source/ruby_on_rails_guides_guidelines.md b/guides/source/ruby_on_rails_guides_guidelines.md index de63e193f4..f5c0ba5b2d 100644 --- a/guides/source/ruby_on_rails_guides_guidelines.md +++ b/guides/source/ruby_on_rails_guides_guidelines.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Ruby on Rails Guides Guidelines =============================== diff --git a/guides/source/security.md b/guides/source/security.md index 4cf6c06f2d..9fbd252bb7 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Securing Rails Applications =========================== @@ -21,13 +21,13 @@ Introduction Web application frameworks are made to help developers build web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. -In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server and the web application itself (and possibly other layers or applications). +In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server, and the web application itself (and possibly other layers or applications). The Gartner Group, however, estimates that 75% of attacks are at the web application layer, and found out "that out of 300 audited sites, 97% are vulnerable to attack". This is because web applications are relatively easy to attack, as they are simple to understand and manipulate, even by the lay person. -The threats against web applications include user account hijacking, bypass of access control, reading or modifying sensitive data, or presenting fraudulent content. Or an attacker might be able to install a Trojan horse program or unsolicited e-mail sending software, aim at financial enrichment or cause brand name damage by modifying company resources. In order to prevent attacks, minimize their impact and remove points of attack, first of all, you have to fully understand the attack methods in order to find the correct countermeasures. That is what this guide aims at. +The threats against web applications include user account hijacking, bypass of access control, reading or modifying sensitive data, or presenting fraudulent content. Or an attacker might be able to install a Trojan horse program or unsolicited e-mail sending software, aim at financial enrichment, or cause brand name damage by modifying company resources. In order to prevent attacks, minimize their impact and remove points of attack, first of all, you have to fully understand the attack methods in order to find the correct countermeasures. That is what this guide aims at. -In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs and make updating and security checks a habit (check the [Additional Resources](#additional-resources) chapter). It is done manually because that's how you find the nasty logical security problems. +In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs, and make updating and security checks a habit (check the [Additional Resources](#additional-resources) chapter). It is done manually because that's how you find the nasty logical security problems. Sessions -------- @@ -74,7 +74,7 @@ Hence, the cookie serves as temporary authentication for the web application. An * Instead of stealing a cookie unknown to the attacker, they fix a user's session identifier (in the cookie) known to them. Read more about this so-called session fixation later. -The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10-$1000 (depending on the available amount of funds), $0.40-$20 for credit card numbers, $1-$8 for online auction site accounts and $4-$30 for email passwords, according to the [Symantec Global Internet Security Threat Report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf). +The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from 0.5%-10% of account balance, $0.5-$30 for credit card numbers ($20-$60 with full details), $0.1-$1.5 for identities (Name, SSN & DOB), $20-$50 for retailer accounts, and $6-$10 for cloud service provider accounts, according to the [Symantec Internet Security Threat Report (2017)](https://www.symantec.com/content/dam/symantec/docs/reports/istr-22-2017-en.pdf). ### Session Guidelines @@ -217,7 +217,7 @@ The best _solution against it is not to store this kind of data in a session, bu NOTE: _Apart from stealing a user's session ID, the attacker may fix a session ID known to them. This is called session fixation._ -![Session fixation](images/session_fixation.png) +![Session fixation](images/security/session_fixation.png) This attack focuses on fixing a user's session ID known to the attacker, and forcing the user's browser into using this ID. It is therefore not necessary for the attacker to steal the session ID afterwards. Here is how this attack works: @@ -244,7 +244,7 @@ Another countermeasure is to _save user-specific properties in the session_, ver ### Session Expiry -NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site request forgery (CSRF), session hijacking and session fixation._ +NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site request forgery (CSRF), session hijacking, and session fixation._ One possibility is to set the expiry time-stamp of the cookie with the session ID. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago. @@ -272,7 +272,7 @@ Cross-Site Request Forgery (CSRF) This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands. -![](images/csrf.png) +![](images/security/csrf.png) In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session ID in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is that if the request comes from a site of a different domain, it will also send the cookie. Let's start with an example: @@ -282,7 +282,7 @@ In the [session chapter](#sessions) you have learned that most Rails application * The web application at `www.webapp.com` verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image. * Bob doesn't notice the attack - but a few days later he finds out that project number one is gone. -It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post or email. +It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post, or email. CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) - less than 0.1% in 2006 - but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in many security contract works - _CSRF is an important security issue_. @@ -302,7 +302,7 @@ The HTTP protocol basically provides two main types of requests - GET and POST ( * The interaction _changes the state_ of the resource in a way that the user would perceive (e.g., a subscription to a service), or * The user is _held accountable for the results_ of the interaction. -If your web application is RESTful, you might be used to additional HTTP verbs, such as PATCH, PUT or DELETE. Some legacy web browsers, however, do not support them - only GET and POST. Rails uses a hidden `_method` field to handle these cases. +If your web application is RESTful, you might be used to additional HTTP verbs, such as PATCH, PUT, or DELETE. Some legacy web browsers, however, do not support them - only GET and POST. Rails uses a hidden `_method` field to handle these cases. _POST requests can be sent automatically, too_. In this example, the link www.harmless.com is shown as the destination in the browser's status bar. But it has actually dynamically created a new form that sends a POST request. @@ -392,7 +392,7 @@ This example is a Base64 encoded JavaScript which displays a simple message box. NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._ -Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so - one more reason to run web servers, database servers and other programs as a less privileged Unix user. +Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so - one more reason to run web servers, database servers, and other programs as a less privileged Unix user. When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all "../" in a file name and an attacker uses a string such as "....//" - the result will be "../". It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master): @@ -419,7 +419,7 @@ WARNING: _Source code in uploaded files may be executed when placed in specific The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file "file.cgi" with code in it, which will be executed when someone downloads the file. -_If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level downwards. +_If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level upwards. ### File Downloads @@ -462,7 +462,7 @@ A real-world example is a [router reconfiguration by CSRF](http://www.h-online.c Another example changed Google Adsense's e-mail address and password. If the victim was logged into Google Adsense, the administration interface for Google advertisement campaigns, an attacker could change the credentials of the victim.
-Another popular attack is to spam your web application, your blog or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination. +Another popular attack is to spam your web application, your blog, or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination. For _countermeasures against CSRF in administration interfaces and Intranet applications, refer to the countermeasures in the CSRF section_. @@ -502,7 +502,7 @@ If the parameter was nil, the resulting SQL query will be SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1 ``` -And thus it found the first user in the database, returned it and logged them in. You can find out more about it in [this blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this. +And thus it found the first user in the database, returned it, and logged them in. You can find out more about it in [this blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this. ### Brute-Forcing Accounts @@ -639,13 +639,13 @@ Injection INFO: _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._ -Injection is very tricky, because the same code or parameter can be malicious in one context, but totally harmless in another. A context can be a scripting, query or programming language, the shell or a Ruby/Rails method. The following sections will cover all important contexts where injection attacks may happen. The first section, however, covers an architectural decision in connection with Injection. +Injection is very tricky, because the same code or parameter can be malicious in one context, but totally harmless in another. A context can be a scripting, query, or programming language, the shell, or a Ruby/Rails method. The following sections will cover all important contexts where injection attacks may happen. The first section, however, covers an architectural decision in connection with Injection. ### Whitelists versus Blacklists -NOTE: _When sanitizing, protecting or verifying something, prefer whitelists over blacklists._ +NOTE: _When sanitizing, protecting, or verifying something, prefer whitelists over blacklists._ -A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_: +A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags, and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_: * Use before_action except: [...] instead of only: [...] for security-related actions. This way you don't forget to enable security checks for newly added actions. * Allow <strong> instead of removing <script> against Cross-Site Scripting (XSS). See below for details. @@ -718,7 +718,7 @@ Also, the second query renames some columns with the AS statement so that the we #### Countermeasures -Ruby on Rails has a built-in filter for special SQL characters, which will escape ' , " , NULL character and line breaks. *Using `Model.find(id)` or `Model.find_by_some thing(something)` automatically applies this countermeasure*. But in SQL fragments, especially *in conditions fragments (`where("...")`), the `connection.execute()` or `Model.find_by_sql()` methods, it has to be applied manually*. +Ruby on Rails has a built-in filter for special SQL characters, which will escape ' , " , NULL character, and line breaks. *Using `Model.find(id)` or `Model.find_by_some thing(something)` automatically applies this countermeasure*. But in SQL fragments, especially *in conditions fragments (`where("...")`), the `connection.execute()` or `Model.find_by_sql()` methods, it has to be applied manually*. Instead of passing a string to the conditions option, you can pass an array to sanitize tainted strings like this: @@ -742,7 +742,7 @@ INFO: _The most widespread, and one of the most devastating security vulnerabili An entry point is a vulnerable URL and its parameters where an attacker can start an attack. -The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications or client-site proxies make it easy to change requests. There are also other attack vectors like banner advertisements. +The most common entry points are message posts, user comments, and guest books, but project titles, document names, and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications or client-site proxies make it easy to change requests. There are also other attack vectors like banner advertisements. XSS attacks work like this: An attacker injects some code, the web application saves it and displays it on a page, later presented to a victim. Most XSS examples simply display an alert box, but it is more powerful than that. XSS can steal the cookie, hijack the session, redirect the victim to a fake website, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information or install malicious software through security holes in the web browser. @@ -785,11 +785,11 @@ The log files on www.attacker.com will read like this: GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2 ``` -You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. HTTP only cookies can be used from IE v6.SP1, Firefox v2.0.0.5, Opera 9.5, Safari 4 and Chrome 1.0.154 onwards. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though. +You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. HTTP only cookies can be used from IE v6.SP1, Firefox v2.0.0.5, Opera 9.5, Safari 4, and Chrome 1.0.154 onwards. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though. ##### Defacement -With web page defacement an attacker can do a lot of things, for example, present false information or lure the victim on the attackers web site to steal the cookie, login credentials or other sensitive data. The most popular way is to include code from external sources by iframes: +With web page defacement an attacker can do a lot of things, for example, present false information or lure the victim on the attackers web site to steal the cookie, login credentials, or other sensitive data. The most popular way is to include code from external sources by iframes: ```html <iframe name="StatPage" src="http://58.xx.xxx.xxx" width=5 height=5 style="display:none"></iframe> @@ -860,9 +860,9 @@ In December 2006, 34,000 actual user names and passwords were stolen in a [MySpa ### CSS Injection -INFO: _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._ +INFO: _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari, and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._ -CSS Injection is explained best by the well-known [MySpace Samy worm](https://samy.pl/popular/tech.html). This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, which created so much traffic that MySpace went offline. The following is a technical explanation of that worm. +CSS Injection is explained best by the well-known [MySpace Samy worm](https://samy.pl/myspace/tech.html). This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, which created so much traffic that MySpace went offline. The following is a technical explanation of that worm. MySpace blocked many tags, but allowed CSS. So the worm's author put JavaScript into CSS like this: @@ -949,9 +949,9 @@ system("/bin/echo","hello; rm *") ### Header Injection -WARNING: _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._ +WARNING: _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS, or HTTP response splitting._ -HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _Remember to escape these header fields, too._ For example when you display the user agent in an administration area. +HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie, and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _Remember to escape these header fields, too._ For example when you display the user agent in an administration area. Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a "referer" field in a form to redirect to the given address: @@ -1089,6 +1089,118 @@ Here is a list of common headers: * **Access-Control-Allow-Origin:** Used to control which sites are allowed to bypass same origin policies and send cross-origin requests. * **Strict-Transport-Security:** [Used to control if the browser is allowed to only access a site over a secure connection](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) +### Content Security Policy + +Rails provides a DSL that allows you to configure a +[Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) +for your application. You can configure a global default policy and then +override it on a per-resource basis and even use lambdas to inject per-request +values into the header such as account subdomains in a multi-tenant application. + +Example global policy: + +```ruby +# config/initializers/content_security_policy.rb +Rails.application.config.content_security_policy do |policy| + policy.default_src :self, :https + policy.font_src :self, :https, :data + policy.img_src :self, :https, :data + policy.object_src :none + policy.script_src :self, :https + policy.style_src :self, :https + + # Specify URI for violation reports + policy.report_uri "/csp-violation-report-endpoint" +end +``` + +Example controller overrides: + +```ruby +# Override policy inline +class PostsController < ApplicationController + content_security_policy do |p| + p.upgrade_insecure_requests true + end +end + +# Using literal values +class PostsController < ApplicationController + content_security_policy do |p| + p.base_uri "https://www.example.com" + end +end + +# Using mixed static and dynamic values +class PostsController < ApplicationController + content_security_policy do |p| + p.base_uri :self, -> { "https://#{current_user.domain}.example.com" } + end +end + +# Disabling the global CSP +class LegacyPagesController < ApplicationController + content_security_policy false, only: :index +end +``` + +Use the `content_security_policy_report_only` +configuration attribute to set +[Content-Security-Policy-Report-Only](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only) +in order to report only content violations for migrating +legacy content + +```ruby +# config/initializers/content_security_policy.rb +Rails.application.config.content_security_policy_report_only = true +``` + +```ruby +# Controller override +class PostsController < ApplicationController + content_security_policy_report_only only: :index +end +``` + +You can enable automatic nonce generation: + +```ruby +# config/initializers/content_security_policy.rb +Rails.application.config.content_security_policy do |policy| + policy.script_src :self, :https +end + +Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } +``` + +Then you can add an automatic nonce value by passing `nonce: true` +as part of `html_options`. Example: + +```html+erb +<%= javascript_tag nonce: true do -%> + alert('Hello, World!'); +<% end -%> +``` + +The same works with `javascript_include_tag`: + +```html+erb +<%= javascript_include_tag "script", nonce: true %> +``` + +Use [`csp_meta_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/CspHelper.html#method-i-csp_meta_tag) +helper to create a meta tag "csp-nonce" with the per-session nonce value +for allowing inline `<script>` tags. + +```html+erb +<head> + <%= csp_meta_tag %> +</head> +``` + +This is used by the Rails UJS helper to create dynamically +loaded inline `<script>` elements. + Environmental Security ---------------------- @@ -1102,7 +1214,7 @@ key that's generated into a version control ignored `config/master.key` — Rail will also look for that key in `ENV["RAILS_MASTER_KEY"]`. Rails also requires the key to boot in production, so the credentials can be read. -To edit stored credentials use `bin/rails credentials:edit`. +To edit stored credentials use `rails credentials:edit`. By default, this file contains the application's `secret_key_base`, but it could also be used to store other credentials such as diff --git a/guides/source/testing.md b/guides/source/testing.md index b9b310cbba..01cda8e6e4 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Testing Rails Applications ========================== @@ -33,8 +33,8 @@ Rails creates a `test` directory for you as soon as you create a Rails project u ```bash $ ls -F test -controllers/ helpers/ mailers/ system/ test_helper.rb -fixtures/ integration/ models/ application_system_test_case.rb +application_system_test_case.rb fixtures/ integration/ models/ test_helper.rb +controllers/ helpers/ mailers/ system/ ``` The `helpers`, `mailers`, and `models` directories are meant to hold tests for view helpers, mailers, and models, respectively. The `controllers` directory is meant to hold tests for controllers, routes, and views. The `integration` directory is meant to hold tests for interactions between controllers. @@ -70,7 +70,7 @@ If you remember, we used the `rails generate model` command in the model, and among other things it created test stubs in the `test` directory: ```bash -$ bin/rails generate model article title:string body:text +$ rails generate model article title:string body:text ... create app/models/article.rb create test/models/article_test.rb @@ -105,7 +105,7 @@ class ArticleTest < ActiveSupport::TestCase The `ArticleTest` class defines a _test case_ because it inherits from `ActiveSupport::TestCase`. `ArticleTest` thus has all the methods available from `ActiveSupport::TestCase`. Later in this guide, we'll see some of the methods it gives us. Any method defined within a class inherited from `Minitest::Test` -(which is the superclass of `ActiveSupport::TestCase`) that begins with `test_` (case sensitive) is simply called a test. So, methods defined as `test_password` and `test_valid_password` are legal test names and are run automatically when the test case is run. +(which is the superclass of `ActiveSupport::TestCase`) that begins with `test_` is simply called a test. So, methods defined as `test_password` and `test_valid_password` are legal test names and are run automatically when the test case is run. Rails also adds a `test` method that takes a test name and a block. It generates a normal `Minitest::Unit` test with method names prefixed with `test_`. So you don't have to worry about naming the methods, and you can write something like: @@ -156,7 +156,7 @@ end Let us run this newly added test (where `6` is the number of line where the test is defined). ```bash -$ bin/rails test test/models/article_test.rb:6 +$ rails test test/models/article_test.rb:6 Run options: --seed 44656 # Running: @@ -168,7 +168,7 @@ ArticleTest#test_should_not_save_article_without_title [/path/to/blog/test/model Expected true to be nil or false -bin/rails test test/models/article_test.rb:6 +rails test test/models/article_test.rb:6 @@ -206,7 +206,7 @@ end Now the test should pass. Let us verify by running the test again: ```bash -$ bin/rails test test/models/article_test.rb:6 +$ rails test test/models/article_test.rb:6 Run options: --seed 31252 # Running: @@ -239,7 +239,7 @@ end Now you can see even more output in the console from running the tests: ```bash -$ bin/rails test test/models/article_test.rb +$ rails test test/models/article_test.rb Run options: --seed 1808 # Running: @@ -252,7 +252,7 @@ NameError: undefined local variable or method 'some_undefined_variable' for #<Ar test/models/article_test.rb:11:in 'block in <class:ArticleTest>' -bin/rails test test/models/article_test.rb:9 +rails test test/models/article_test.rb:9 @@ -276,7 +276,7 @@ code. However there are situations when you want to see the full backtrace. Set the `-b` (or `--backtrace`) argument to enable this behavior: ```bash -$ bin/rails test -b test/models/article_test.rb +$ rails test -b test/models/article_test.rb ``` If we want this test to pass we can modify it to use `assert_raises` like so: @@ -381,12 +381,12 @@ documentation](http://docs.seattlerb.org/minitest). ### The Rails Test Runner -We can run all of our tests at once by using the `bin/rails test` command. +We can run all of our tests at once by using the `rails test` command. -Or we can run a single test file by passing the `bin/rails test` command the filename containing the test cases. +Or we can run a single test file by passing the `rails test` command the filename containing the test cases. ```bash -$ bin/rails test test/models/article_test.rb +$ rails test test/models/article_test.rb Run options: --seed 1559 # Running: @@ -404,7 +404,7 @@ You can also run a particular test method from the test case by providing the `-n` or `--name` flag and the test's method name. ```bash -$ bin/rails test test/models/article_test.rb -n test_the_truth +$ rails test test/models/article_test.rb -n test_the_truth Run options: -n test_the_truth --seed 43583 # Running: @@ -419,47 +419,48 @@ Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s. You can also run a test at a specific line by providing the line number. ```bash -$ bin/rails test test/models/article_test.rb:6 # run specific test and line +$ rails test test/models/article_test.rb:6 # run specific test and line ``` You can also run an entire directory of tests by providing the path to the directory. ```bash -$ bin/rails test test/controllers # run all tests from specific directory +$ rails test test/controllers # run all tests from specific directory ``` The test runner also provides a lot of other features like failing fast, deferring test output at the end of test run and so on. Check the documentation of the test runner as follows: ```bash -$ bin/rails test -h -minitest options: - -h, --help Display this help. - -s, --seed SEED Sets random seed. Also via env. Eg: SEED=n rake - -v, --verbose Verbose. Show progress processing files. - -n, --name PATTERN Filter run on /regexp/ or string. - --exclude PATTERN Exclude /regexp/ or string from run. - -Known extensions: rails, pride +$ rails test -h +Usage: rails test [options] [files or directories] -Usage: bin/rails test [options] [files or directories] You can run a single test by appending a line number to a filename: - bin/rails test test/models/user_test.rb:27 + rails test test/models/user_test.rb:27 You can run multiple files and directories at the same time: - bin/rails test test/controllers test/integration/login_test.rb + rails test test/controllers test/integration/login_test.rb By default test failures and errors are reported inline during a run. -Rails options: +minitest options: + -h, --help Display this help. + --no-plugins Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS). + -s, --seed SEED Sets random seed. Also via env. Eg: SEED=n rake + -v, --verbose Verbose. Show progress processing files. + -n, --name PATTERN Filter run on /regexp/ or string. + --exclude PATTERN Exclude /regexp/ or string from run. + +Known extensions: rails, pride -w, --warnings Run with Ruby warnings enabled - -e, --environment Run tests in the ENV environment + -e, --environment ENV Run tests in the ENV environment -b, --backtrace Show the complete backtrace -d, --defer-output Output test failures and errors after the test run -f, --fail-fast Abort test run on first failure or error -c, --[no-]color Enable color in the output + -p, --pride Pride. Show your testing pride! ``` Parallel Testing @@ -489,7 +490,7 @@ parallelize your local test suite differently from your CI, so an environment va to be able to easily change the number of workers a test run should use: ``` -PARALLEL_WORKERS=15 bin/rails test +PARALLEL_WORKERS=15 rails test ``` When parallelizing tests, Active Record automatically handles creating and migrating a database for each @@ -503,7 +504,7 @@ Two hooks are provided, one runs when the process is forked, and one runs before These can be useful if your app uses multiple databases or perform other tasks that depend on the number of workers. -The `parallelize_setup` method is called right after the processes are forked. The `parallelize_teardown` metod +The `parallelize_setup` method is called right after the processes are forked. The `parallelize_teardown` method is called right before the processes are closed. ``` @@ -542,7 +543,7 @@ want to parallelize your local test suite differently from your CI, so an enviro to be able to easily change the number of workers a test run should use: ``` -PARALLEL_WORKERS=15 bin/rails test +PARALLEL_WORKERS=15 rails test ``` The Test Database @@ -562,11 +563,11 @@ structure. The test helper checks whether your test database has any pending migrations. It will try to load your `db/schema.rb` or `db/structure.sql` into the test database. If migrations are still pending, an error will be raised. Usually this indicates that your schema is not fully migrated. Running -the migrations against the development database (`bin/rails db:migrate`) will +the migrations against the development database (`rails db:migrate`) will bring the schema up to date. NOTE: If there were modifications to existing migrations, the test database needs to -be rebuilt. This can be done by executing `bin/rails db:test:prepare`. +be rebuilt. This can be done by executing `rails db:test:prepare`. ### The Low-Down on Fixtures @@ -679,7 +680,7 @@ Rails model tests are stored under the `test/models` directory. Rails provides a generator to create a model test skeleton for you. ```bash -$ bin/rails generate test_unit:model article title:string body:text +$ rails generate test_unit:model article title:string body:text create test/models/article_test.rb create test/fixtures/articles.yml ``` @@ -690,13 +691,13 @@ System Testing -------------- System tests allow you to test user interactions with your application, running tests -in either a real or a headless browser. System tests uses Capybara under the hood. +in either a real or a headless browser. System tests use Capybara under the hood. For creating Rails system tests, you use the `test/system` directory in your application. Rails provides a generator to create a system test skeleton for you. ```bash -$ bin/rails generate system_test users +$ rails generate system_test users invoke test_unit create test/system/users_test.rb ``` @@ -797,7 +798,7 @@ created for you. If you didn't use the scaffold generator, start by creating a system test skeleton. ```bash -$ bin/rails generate system_test articles +$ rails generate system_test articles ``` It should have created a test file placeholder for us. With the output of the @@ -826,11 +827,11 @@ The test should see that there is an `h1` on the articles index page and pass. Run the system tests. ```bash -bin/rails test:system +rails test:system ``` -NOTE: By default, running `bin/rails test` won't run your system tests. -Make sure to run `bin/rails test:system` to actually run them. +NOTE: By default, running `rails test` won't run your system tests. +Make sure to run `rails test:system` to actually run them. #### Creating articles system test @@ -909,7 +910,7 @@ Integration tests are used to test how various parts of your application interac For creating Rails integration tests, we use the `test/integration` directory for our application. Rails provides a generator to create an integration test skeleton for us. ```bash -$ bin/rails generate integration_test user_flows +$ rails generate integration_test user_flows exists test/integration/ create test/integration/user_flows_test.rb ``` @@ -945,7 +946,7 @@ Let's add an integration test to our blog application. We'll start with a basic We'll start by generating our integration test skeleton: ```bash -$ bin/rails generate integration_test blog_flow +$ rails generate integration_test blog_flow ``` It should have created a test file placeholder for us. With the output of the @@ -1033,7 +1034,7 @@ You should test for things such as: The easiest way to see functional tests in action is to generate a controller using the scaffold generator: ```bash -$ bin/rails generate scaffold_controller article title:string body:text +$ rails generate scaffold_controller article title:string body:text ... create app/controllers/articles_controller.rb ... @@ -1049,7 +1050,7 @@ If you already have a controller and just want to generate the test scaffold cod each of the seven default actions, you can use the following command: ```bash -$ bin/rails generate test_unit:scaffold article +$ rails generate test_unit:scaffold article ... invoke test_unit create test/controllers/articles_controller_test.rb @@ -1084,16 +1085,16 @@ The `get` method kicks off the web request and populates the results into the `@ All of these keyword arguments are optional. -Example: Calling the `:show` action, passing an `id` of 12 as the `params` and setting `HTTP_REFERER` header: +Example: Calling the `:show` action for the first `Article`, passing in an `HTTP_REFERER` header: ```ruby -get article_url, params: { id: 12 }, headers: { "HTTP_REFERER" => "http://example.com/home" } +get article_url(Article.first), headers: { "HTTP_REFERER" => "http://example.com/home" } ``` -Another example: Calling the `:update` action, passing an `id` of 12 as the `params` as an Ajax request. +Another example: Calling the `:update` action for the last `Article`, passing in new text for the `title` in `params`, as an Ajax request: ```ruby -patch article_url, params: { id: 12 }, xhr: true +patch article_url(Article.last), params: { article: { title: "updated" } }, xhr: true ``` NOTE: If you try running `test_should_create_article` test from `articles_controller_test.rb` it will fail on account of the newly added model level validation and rightly so. @@ -1130,7 +1131,7 @@ If you're familiar with the HTTP protocol, you'll know that `get` is a type of r * `head` * `delete` -All of request types have equivalent methods that you can use. In a typical C.R.U.D. application you'll be using `get`, `post`, `put` and `delete` more often. +All of request types have equivalent methods that you can use. In a typical C.R.U.D. application you'll be using `get`, `post`, `put`, and `delete` more often. NOTE: Functional tests do not verify whether the specified request type is accepted by the action, we're more concerned with the result. Request tests exist for this use case to make your tests more purposeful. @@ -1224,7 +1225,7 @@ end If we run our test now, we should see a failure: ```bash -$ bin/rails test test/controllers/articles_controller_test.rb -n test_should_create_article +$ rails test test/controllers/articles_controller_test.rb -n test_should_create_article Run options: -n test_should_create_article --seed 32266 # Running: @@ -1262,7 +1263,7 @@ end Now if we run our tests, we should see it pass: ```bash -$ bin/rails test test/controllers/articles_controller_test.rb -n test_should_create_article +$ rails test test/controllers/articles_controller_test.rb -n test_should_create_article Run options: -n test_should_create_article --seed 18981 # Running: @@ -1475,7 +1476,7 @@ Testing Helpers --------------- A helper is just a simple module where you can define methods which are -available into your views. +available in your views. In order to test helpers, all you need to do is check that the output of the helper method matches what you'd expect. Tests related to the helpers are @@ -1484,7 +1485,7 @@ located under the `test/helpers` directory. Given we have the following helper: ```ruby -module UserHelper +module UsersHelper def link_to_user(user) link_to "#{user.first_name} #{user.last_name}", user end @@ -1494,7 +1495,7 @@ end We can test the output of this method like this: ```ruby -class UserHelperTest < ActionView::TestCase +class UsersHelperTest < ActionView::TestCase test "should return the user's full name" do user = users(:david) @@ -1595,12 +1596,12 @@ manually with: `ActionMailer::Base.deliveries.clear` ### Functional Testing -Functional testing for mailers involves more than just checking that the email body, recipients and so forth are correct. In functional mail tests you call the mail deliver methods and check that the appropriate emails have been appended to the delivery list. It is fairly safe to assume that the deliver methods themselves do their job. You are probably more interested in whether your own business logic is sending emails when you expect them to go out. For example, you can check that the invite friend operation is sending an email appropriately: +Functional testing for mailers involves more than just checking that the email body, recipients, and so forth are correct. In functional mail tests you call the mail deliver methods and check that the appropriate emails have been appended to the delivery list. It is fairly safe to assume that the deliver methods themselves do their job. You are probably more interested in whether your own business logic is sending emails when you expect them to go out. For example, you can check that the invite friend operation is sending an email appropriately: ```ruby require 'test_helper' -class UserControllerTest < ActionDispatch::IntegrationTest +class UsersControllerTest < ActionDispatch::IntegrationTest test "invite friend" do assert_difference 'ActionMailer::Base.deliveries.size', +1 do post invite_friend_url, params: { email: 'friend@example.com' } diff --git a/guides/source/threading_and_code_execution.md b/guides/source/threading_and_code_execution.md index e4febc7507..d3a81fe6a8 100644 --- a/guides/source/threading_and_code_execution.md +++ b/guides/source/threading_and_code_execution.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Threading and Code Execution in Rails ===================================== diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index d5dfaef591..319bc09be3 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Upgrading Ruby on Rails ======================= @@ -45,8 +45,8 @@ TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterp ### The Update Task -Rails provides the `app:update` task (`rake rails:update` on 4.2 and earlier). After updating the Rails version -in the `Gemfile`, run this task. +Rails provides the `app:update` command (`rake rails:update` on 4.2 and earlier). After updating the Rails version +in the `Gemfile`, run this command. This will help you with the creation of new files and changes of old files in an interactive session. @@ -66,6 +66,17 @@ Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh] Don't forget to review the difference, to see if there were any unexpected changes. +Upgrading from Rails 5.2 to Rails 6.0 +------------------------------------- + +### Force SSL + +The `force_ssl` method on controllers has been deprecated and will be removed in +Rails 6.1. You are encouraged to enable `config.force_ssl` to enforce HTTPS +connections throughout your application. If you need to exempt certain endpoints +from redirection, you can use `config.ssl_options` to configure that behavior. + + Upgrading from Rails 5.1 to Rails 5.2 ------------------------------------- @@ -74,7 +85,7 @@ For more information on changes made to Rails 5.2 please see the [release notes] ### Bootsnap Rails 5.2 adds bootsnap gem in the [newly generated app's Gemfile](https://github.com/rails/rails/pull/29313). -The `app:update` task sets it up in `boot.rb`. If you want to use it, then add it in the Gemfile, +The `app:update` command sets it up in `boot.rb`. If you want to use it, then add it in the Gemfile, otherwise change the `boot.rb` to not use bootsnap. ### Expiry in signed or encrypted cookie is now embedded in the cookies values @@ -246,16 +257,18 @@ it. `debugger` is not supported by Ruby 2.2 which is required by Rails 5. Use `byebug` instead. -### Use bin/rails for running tasks and tests +### Use `rails` for running tasks and tests Rails 5 adds the ability to run tasks and tests through `bin/rails` instead of rake. Generally -these changes are in parallel with rake, but some were ported over altogether. +these changes are in parallel with rake, but some were ported over altogether. As the `rails` +command already looks for and runs `bin/rails`, we recommend you to use the shorter `rails` +over `bin/rails. -To use the new test runner simply type `bin/rails test`. +To use the new test runner simply type `rails test`. `rake dev:cache` is now `rails dev:cache`. -Run `bin/rails` to see the list of commands available. +Run `rails` inside your application's directory to see the list of commands available. ### `ActionController::Parameters` No Longer Inherits from `HashWithIndifferentAccess` @@ -1121,7 +1134,7 @@ being used, you can update your form to use the `PUT` method instead: <%= form_for [ :update_name, @user ], method: :put do |f| %> ``` -For more on PATCH and why this change was made, see [this post](http://weblog.rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates/) +For more on PATCH and why this change was made, see [this post](https://weblog.rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates/) on the Rails blog. #### A note about media types @@ -1343,6 +1356,17 @@ config.middleware.insert_before(Rack::Lock, ActionDispatch::BestStandardsSupport Also check your environment settings for `config.action_dispatch.best_standards_support` and remove it if present. +* Rails 4.0 allows configuration of HTTP headers by setting `config.action_dispatch.default_headers`. The defaults are as follows: + +```ruby + config.action_dispatch.default_headers = { + 'X-Frame-Options' => 'SAMEORIGIN', + 'X-XSS-Protection' => '1; mode=block' + } +``` + +Please note that if your application is dependent on loading certain pages in a `<frame>` or `<iframe>`, then you may need to explicitly set `X-Frame-Options` to `ALLOW-FROM ...` or `ALLOWALL`. + * In Rails 4.0, precompiling assets no longer automatically copies non-JS/CSS assets from `vendor/assets` and `lib/assets`. Rails application and engine developers should put these assets in `app/assets` or configure `config.assets.precompile`. * In Rails 4.0, `ActionController::UnknownFormat` is raised when the action doesn't handle the request format. By default, the exception is handled by responding with 406 Not Acceptable, but you can override that now. In Rails 3, 406 Not Acceptable was always returned. No overrides. @@ -1366,7 +1390,7 @@ Rails 4.0 removes the `j` alias for `ERB::Util#json_escape` since `j` is already #### Cache -The caching method changed between Rails 3.x and 4.0. You should [change the cache namespace](http://guides.rubyonrails.org/caching_with_rails.html#activesupport-cache-store) and roll out with a cold cache. +The caching method changed between Rails 3.x and 4.0. You should [change the cache namespace](https://guides.rubyonrails.org/caching_with_rails.html#activesupport-cache-store) and roll out with a cold cache. ### Helpers Loading Order diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index b9ea4ad47a..36f5039883 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Working with JavaScript in Rails ================================ @@ -382,10 +382,9 @@ have been bundled into `event.detail`. For information about the previously used `jquery-ujs` in Rails 5 and earlier, read the [`jquery-ujs` wiki](https://github.com/rails/jquery-ujs/wiki/ajax). ### Stoppable events - -If you stop `ajax:before` or `ajax:beforeSend` by returning false from the -handler method, the Ajax request will never take place. The `ajax:before` event -can manipulate form data before serialization and the +You can stop execution of the Ajax request by running `event.preventDefault()` +from the handlers methods `ajax:before` or `ajax:beforeSend`. +The `ajax:before` event can manipulate form data before serialization and the `ajax:beforeSend` event is useful for adding custom request headers. If you stop the `ajax:aborted:file` event, the default behavior of allowing the @@ -393,6 +392,9 @@ browser to submit the form via normal means (i.e. non-Ajax submission) will be canceled and the form will not be submitted at all. This is useful for implementing your own Ajax file upload workaround. +Note, you should use `return false` to prevent event for `jquery-ujs` and +`e.preventDefault()` for `rails-ujs` + Server-Side Concerns -------------------- |