diff options
Diffstat (limited to 'guides')
-rw-r--r-- | guides/source/active_model_basics.textile | 4 | ||||
-rw-r--r-- | guides/source/active_record_querying.textile | 18 | ||||
-rw-r--r-- | guides/source/active_support_core_extensions.textile | 30 | ||||
-rw-r--r-- | guides/source/ajax_on_rails.textile | 4 | ||||
-rw-r--r-- | guides/source/asset_pipeline.textile | 37 | ||||
-rw-r--r-- | guides/source/configuring.textile | 2 | ||||
-rw-r--r-- | guides/source/getting_started.textile | 291 | ||||
-rw-r--r-- | guides/source/i18n.textile | 6 | ||||
-rw-r--r-- | guides/source/layouts_and_rendering.textile | 6 | ||||
-rw-r--r-- | guides/source/migrations.textile | 16 |
10 files changed, 237 insertions, 177 deletions
diff --git a/guides/source/active_model_basics.textile b/guides/source/active_model_basics.textile index f140a8d2ac..d373f4ac85 100644 --- a/guides/source/active_model_basics.textile +++ b/guides/source/active_model_basics.textile @@ -20,7 +20,7 @@ class Person attribute_method_prefix 'reset_' attribute_method_suffix '_highest?' - define_attribute_methods ['age'] + define_attribute_methods 'age' attr_accessor :age @@ -99,7 +99,7 @@ require 'active_model' class Person include ActiveModel::Dirty - define_attribute_methods [:first_name, :last_name] + define_attribute_methods :first_name, :last_name def first_name @first_name diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile index a9cb424eaa..294ef25b33 100644 --- a/guides/source/active_record_querying.textile +++ b/guides/source/active_record_querying.textile @@ -1260,6 +1260,24 @@ with Client.pluck(:id) </ruby> +h3. +ids+ + ++ids+ can be used to pluck all the IDs for the relation using the table's primary key. + +<ruby> +Person.ids +# SELECT id FROM people +</ruby> + +<ruby> +class Person < ActiveRecord::Base + self.primary_key = "person_id" +end + +Person.ids +# SELECT person_id FROM people +</ruby> + h3. Existence of Objects If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+. diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile index 8045316e98..6443255f5d 100644 --- a/guides/source/active_support_core_extensions.textile +++ b/guides/source/active_support_core_extensions.textile @@ -1277,20 +1277,6 @@ The <tt>inquiry</tt> method converts a string into a +StringInquirer+ object mak "active".inquiry.inactive? # => false </ruby> -h4. Key-based Interpolation - -In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted: - -<ruby> -"Total is %<total>.02f" % {:total => 43.1} # => Total is 43.10 -"I say %{foo}" % {:foo => "wadus"} # => "I say wadus" -"I say %{woo}" % {:foo => "wadus"} # => KeyError -</ruby> - -Active Support adds that functionality to <tt>%</tt> in previous versions of Ruby. - -NOTE: Defined in +active_support/core_ext/string/interpolation.rb+. - h4. +starts_with?+ and +ends_with?+ Active Support defines 3rd person aliases of +String#start_with?+ and +String#end_with?+: @@ -1337,7 +1323,7 @@ Returns the character of the string at position +position+: "hello".at(0) # => "h" "hello".at(4) # => "o" "hello".at(-1) # => "o" -"hello".at(10) # => ERROR if < 1.9, nil in 1.9 +"hello".at(10) # => nil </ruby> NOTE: Defined in +active_support/core_ext/string/access.rb+. @@ -1819,7 +1805,7 @@ NOTE: Defined in +active_support/core_ext/numeric/bytes.rb+. h4. Time -Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. +Enables the use of time calculations and declarations, like @45.minutes <plus> 2.hours <plus> 4.years@. These methods use Time#advance for precise date calculations when using from_now, ago, etc. as well as adding or subtracting their results from a Time object. For example: @@ -2767,18 +2753,6 @@ As the example depicts, the +:db+ format generates a +BETWEEN+ SQL clause. That NOTE: Defined in +active_support/core_ext/range/conversions.rb+. -h4. +step+ - -Active Support extends the method +Range#step+ so that it can be invoked without a block: - -<ruby> -(1..10).step(2) # => [1, 3, 5, 7, 9] -</ruby> - -As the example shows, in that case the method returns an array with the corresponding elements. - -NOTE: Defined in +active_support/core_ext/range/blockless_step.rb+. - h4. +include?+ The methods +Range#include?+ and +Range#===+ say whether some value falls between the ends of a given instance: diff --git a/guides/source/ajax_on_rails.textile b/guides/source/ajax_on_rails.textile index cda9c64460..bfd007490a 100644 --- a/guides/source/ajax_on_rails.textile +++ b/guides/source/ajax_on_rails.textile @@ -78,7 +78,7 @@ will produce <ruby> button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?', - :method => "delete", :remote => true, :disable_with => 'loading...') + :method => "delete", :remote => true, 'data-disable-with' => 'loading...') </ruby> will produce @@ -87,7 +87,7 @@ will produce <form class='button_to' method='post' action='http://www.example.com' data-remote='true'> <div> <input name='_method' value='delete' type='hidden' /> - <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' /> + <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' /> </div> </form> </html> diff --git a/guides/source/asset_pipeline.textile b/guides/source/asset_pipeline.textile index 010154f1d1..105efe229e 100644 --- a/guides/source/asset_pipeline.textile +++ b/guides/source/asset_pipeline.textile @@ -396,7 +396,7 @@ Rails comes bundled with a rake task to compile the asset manifests and other fi Compiled assets are written to the location specified in +config.assets.prefix+. By default, this is the +public/assets+ directory. -You can call this task on the server during deployment to create compiled versions of your assets directly on the server. If you do not have write access to your production file system, you can call this task locally and then deploy the compiled assets. +You can call this task 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 rake task is: @@ -516,6 +516,41 @@ If you're compiling nginx with Phusion Passenger you'll need to pass that option A robust configuration for Apache is possible but tricky; please Google around. (Or help update this Guide if you have a good example configuration for Apache.) +h4. Local Precompilation + +There are several reasons why you might want to precompile your assets locally. Among them are: + +* You may not have write access to your production file system. +* You may be deploying to more than one server, and want to avoid the duplication of work. +* You may be doing frequent deploys that do not include asset changes. + +Local compilation allows you to commit the compiled files into source control, and deploy as normal. + +There are two caveats: + +* You must not run the Capistrano deployment task that precompiles assets. +* You must change the following two application configuration settings. + +In <tt>config/environments/development.rb</tt>, place the following line: + +<erb> +config.assets.prefix = "/dev-assets" +</erb> + +You will also need this in application.rb: + +<erb> +config.assets.initialize_on_precompile = false +</erb> + +The +prefix+ change makes Rails use a different URL for serving assets in development mode, and pass all requests to Sprockets. The prefix is still set to +/assets+ in the production environment. Without this change, the application would serve the precompiled assets from +public/assets+ in development, and you would not see any local changes until you compile assets again. + +The +initialize_on_precompile+ change tells the precompile task to run without invoking Rails. This is because the precompile task runs in production mode by default, and will attempt to connect to your specified production database. Please note that you cannot have code in pipeline files that relies on Rails resources (such as the database) when compiling locally with this option. + +You will also need to ensure that any compressors or minifiers are available on your development system. + +In practice, this will allow you to precompile locally, have those files in your working tree, and commit those files to source control when needed. Development mode will work as expected. + h4. Live Compilation In some circumstances you may wish to use live compilation. In this mode all requests for assets in the pipeline are handled by Sprockets directly. diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile index b2c9300034..f114075cae 100644 --- a/guides/source/configuring.textile +++ b/guides/source/configuring.textile @@ -597,7 +597,7 @@ Rails has 5 initialization events which can be hooked into (listed in the order * +to_prepare+: Run after the initializers are run for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in +development+, but only once (during boot-up) in +production+ and +test+. -* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment. +* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the +production+ environment and not for the +development+ environment. * +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run. diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 1e9bd1f144..19bd106ff0 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -183,9 +183,9 @@ Rails will create several files for you. Most important of these are of course t Open the +app/views/welcome/index.html.erb+ file in your text editor and edit it to contain a single line of code: -<code class="html"> +<html> <h1>Hello, Rails!</h1> -</code> +</html> h4. Setting the Application Home Page @@ -193,7 +193,7 @@ Now that we have made the controller and view, we need to tell Rails when we wan To fix this, delete the +index.html+ file located inside the +public+ directory of the application. -You need to do this because Rails will serve any static file in the +public+ directory that matches a route in preference to any dynamic content you generate from the controllers. +You need to do this because Rails will serve any static file in the +public+ directory that matches a route in preference to any dynamic content you generate from the controllers. The +index.html+ file is special: it will be served if a request comes in at the root route, e.g. http://localhost:3000. If another request such as http://localhost:3000/welcome happened, a static file at <tt>public/welcome.html</tt> would be served first, but only if it existed. Next, you have to tell Rails where your actual home page is located. @@ -210,7 +210,7 @@ Blog::Application.routes.draw do The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+). -If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see +Hello, Rails!+. +If you navigate to "http://localhost:3000":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+ action and is rendering the view correctly. NOTE. For more information about routing, refer to "Rails Routing from the Outside In":routing.html. @@ -220,7 +220,7 @@ Now that you've seen how to create a controller, an action and a view, let's cre In the Blog application, you will now create a new _resource_. A resource is the term used for a collection of similar objects, such as posts, people or animals. You can create, read, update and destroy items for a resource and these operations are referred to as _CRUD_ operations. -In the next section, you will add the ability to create new posts in your application and be able to view them. This is the "CR" from CRUD. The form for doing this will look like this: +In the next section, you will add the ability to create new posts in your application and be able to view them. This is the "C" and the "R" from CRUD: creation and reading. The form for doing this will look like this: !images/getting_started/new_post.png(The new post form)! @@ -232,7 +232,7 @@ The first thing that you are going to need to create a new post within the appli !images/getting_started/routing_error_no_route_matches.png(A routing error, no route matches /posts/new)! -This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, and so you must define your routes as you need them. +This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, besides the root route you defined earlier, and so you must define your routes as you need them. To do this, you're going to need to create a route inside +config/routes.rb+ file, on a new line between the +do+ and the +end+ for the +draw+ method: @@ -282,9 +282,9 @@ You're getting this error now because Rails expects plain actions like this one In the above image, the bottom line has been truncated. Let's see what the full thing looks like: -<text> +<blockquote> Missing template posts/new, application/new with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "/path/to/blog/app/views" -</text> +</blockquote> That's quite a lot of text! Let's quickly go through and understand what each part of it does. @@ -330,11 +330,17 @@ method called +form_for+. To use this method, add this code into +app/views/post If you refresh the page now, you'll see the exact same form as in the example. Building forms in Rails is really just that easy! -When you call +form_for+, you pass it an identifying object for this form. In this case, it's the symbol +:post+. This tells the +form_for+ helper what this form is for. Inside the block for this method, the FormBuilder object -- represented by +f+ -- is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to +submit+ on the +f+ object will create a submit button for the form. +When you call +form_for+, you pass it an identifying object for this +form. In this case, it's the symbol +:post+. This tells the +form_for+ +helper what this form is for. Inside the block for this method, the ++FormBuilder+ object -- represented by +f+ -- is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to +submit+ on the +f+ object will create a submit button for the form. There's one problem with this form though. If you inspect the HTML that is generated, by viewing the source of the page, you will see that the +action+ attribute for the form is pointing at +/posts/new+. This is a problem because this route goes to the very page that you're on right at the moment, and that route should only be used to display the form for a new post. -So the form needs to use a different URL in order to go somewhere else. This can be done quite simply with the +:url+ option of +form_for+. Typically in Rails, the action that is used for new form submissions like this is called "create", and so the form should be pointed to this action. +The form needs to use a different URL in order to go somewhere else. +This can be done quite simply with the +:url+ option of +form_for+. +Typically in Rails, the action that is used for new form submissions +like this is called "create", and so the form should be pointed to that action. Edit the +form_for+ line inside +app/views/posts/new.html.erb+ to look like this: @@ -350,11 +356,11 @@ post "posts/create" By using the +post+ method rather than the +get+ method, Rails will define a route that will only respond to POST methods. The POST method is the typical method used by forms all over the web. -With the form and the route for it defined now, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error: +With the form and its associated route defined, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error: !images/getting_started/unknown_action_create_for_posts.png(Unknown action create for PostsController)! -You will now need to create the +create+ action within the +PostsController+ for this to work. +You now need to create the +create+ action within the +PostsController+ for this to work. h4. Creating posts @@ -381,7 +387,7 @@ def create end </ruby> -The +render+ method here is taking a very simple hash with the key of +text+ and the value of +params[:post].inspect+. The +params+ method here is the object which represents the parameters (or fields) coming in from the form. The +params+ method returns a +HashWithIndifferentAccess+ object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form. +The +render+ method here is taking a very simple hash with a key of +text+ and value of +params[:post].inspect+. The +params+ method is the object which represents the parameters (or fields) coming in from the form. The +params+ method returns a +HashWithIndifferentAccess+ object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form. If you re-submit the form one more time you'll now no longer get the missing template error. Instead, you'll see something that looks like the following: @@ -402,16 +408,22 @@ To create the new model, run this command in your terminal: $ rails generate model Post title:string text:text </shell> -With that command we told Rails that we want a +Post+ model, which in -turn should have a title attribute of type string, and a text attribute +With that command we told Rails that we want a +Post+ model, together +with a _title_ attribute of type string, and a _text_ attribute of type text. Those attributes are automatically added to the +posts+ table in the database and mapped to the +Post+ model. -Rails in turn responded by creating a bunch of files. For +Rails responded by creating a bunch of files. For now, we're only interested in +app/models/post.rb+ and -+db/migrate/20120419084633_create_posts.rb+. The latter is responsible ++db/migrate/20120419084633_create_posts.rb+ (your name could be a bit +different). The latter is responsible for creating the database structure, which is what we'll look at next. +TIP: Active Record is smart enough to automatically map column names to +model attributes, which means you don't have to declare attributes +inside Rails models, as that will be done automatically by Active +Record. + h4. Running a Migration As we've just seen, +rails generate model+ created a _database @@ -472,8 +484,8 @@ invoking the command: +rake db:migrate RAILS_ENV=production+. h4. Saving data in the controller Back in +posts_controller+, we need to change the +create+ action -to use the new +Post+ model to save data in the database. Open that file -and change the +create+ action to look like the following: +to use the new +Post+ model to save the data in the database. Open that file +and change the +create+ action to look like this: <ruby> def create @@ -485,22 +497,21 @@ end </ruby> Here's what's going on: every Rails model can be initialized with its -respective attributes, which are automatically mapped to its +respective attributes, which are automatically mapped to the respective database columns. In the first line we do just that (remember that +params[:post]+ contains the attributes we're interested in). Then, +@post.save+ is responsible for saving the model in the database. -Finally, on the last line we redirect the user to the +show+ action, -wich we have not defined yet. +Finally, we redirect the user to the +show+ action, +wich we'll define later. TIP: As we'll see later, +@post.save+ returns a boolean indicating -wherever the model was saved or not, and you can (and usually do) take -different actions depending on the result of calling +@post.save+. +wherever the model was saved or not. -h4. Showing posts +h4. Showing Posts -Before trying to create a new post, let's add the +show+ action, which -will be responsible for showing our posts. Open +config/routes.rb+ -and add the following route: +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. Open +config/routes.rb+ and add the following route: <ruby> get "posts/:id" => "posts#show" @@ -549,19 +560,21 @@ be able to create a post. Try it! h4. Listing all posts We still need a way to list all our posts, so let's do that. As usual, -we'll need a route, a controller action, and a view: +we'll need a route placed into +config/routes.rb+: <ruby> -# Add to config/routes.rb get "posts" => "posts#index" +</ruby> + +And an action for that route inside the +PostsController+ in the +app/controllers/posts_controller.rb+ file: -# Add to app/controllers/posts_controller.rb +<ruby> def index @posts = Post.all end </ruby> -+app/view/posts/index.html.erb+: +And then finally a view for this action, located at +app/views/posts/index.html.erb+: <erb> <h1>Listing posts</h1> @@ -572,15 +585,17 @@ end <th>Text</th> </tr> -<% @posts.each do |post| %> - <tr> - <td><%= post.title %></td> - <td><%= post.text %></td> - </tr> -<% end %> + <% @posts.each do |post| %> + <tr> + <td><%= post.title %></td> + <td><%= post.text %></td> + </tr> + <% end %> </table> </erb> +Now if you go to +http://localhost:3000/posts+ you will see a list of all the posts that you have created. + h4. Adding links You can now create, show, and list posts. Now let's add some links to @@ -597,41 +612,25 @@ The +link_to+ method is one of Rails' built-in view helpers. It creates a hyperlink based on text to display and where to go - in this case, to the path for posts. -Let's add links to the other views as well. +Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +<table>+ tag: <erb> -# app/views/posts/index.html.erb - -<h1>Listing posts</h1> - <%= link_to 'New post', :action => :new %> +</erb> -<table> - <tr> - <th>Title</th> - <th>Text</th> - <th></th> - </tr> - -<% @posts.each do |post| %> - <tr> - <td><%= post.title %></td> - <td><%= post.text %></td> - <td><%= link_to 'Show', :action => :show, :id => post.id %></td> - </tr> -<% end %> -</table> - -# app/views/posts/new.html.erb +This link will allow you to bring up the form that lets you create a new post. You should also add a link to this template -- +app/views/posts/new.html.erb+ -- to go back to the +index+ action. Do this by adding this underneath the form in this template: +<erb> <%= form_for :post do |f| %> ... <% end %> <%= link_to 'Back', :action => :index %> +</erb> -# app/views/posts/show.html.erb +Finally, add another link to the +app/views/posts/show.html.erb+ template to go back to the +index+ action as well, so that people who are viewing a single post can go back and view the whole list again: +<erb> <p> <strong>Title:</strong> <%= @post.title %> @@ -653,7 +652,7 @@ TIP: In development mode (which is what you're working in by default), Rails reloads your application with every browser request, so there's no need to stop and restart the web server when a change is made. -h4. Adding Some Validation +h4. Allowing the update of fields The model file, +app/models/post.rb+ is about as simple as it can get: @@ -668,11 +667,28 @@ your Rails models for free, including basic database CRUD (Create, Read, Update, Destroy) operations, data validation, as well as sophisticated search support and the ability to relate multiple models to one another. +Rails includes methods to help you secure some of your model fields. +Open the +app/models/post.rb+ file and edit it: + +<ruby> +class Post < ActiveRecord::Base + attr_accessible :text, :title +end +</ruby> + +This change will ensure that all changes made through HTML forms can edit the content of the text and title fields. +It will not be possible to define any other field value through forms. You can still define them by calling the `field=` method of course. +Accessible attributes and the mass assignment probem is covered in details in the "Security guide":security.html#mass-assignment + +h4. Adding Some Validation + Rails includes methods to help you validate the data that you send to models. Open the +app/models/post.rb+ file and edit it: <ruby> class Post < ActiveRecord::Base + attr_accessible :text, :title + validates :title, :presence => true, :length => { :minimum => 5 } end @@ -684,9 +700,12 @@ format, and the existence of associated objects. Validations are covered in deta in "Active Record Validations and Callbacks":active_record_validations_callbacks.html#validations-overview -If you open +posts_controller+ again, you'll notice that we don't check -the result of calling +@post.save+. We need to change its behavior to -show the form back to the user if any error occur: +With the validation now in place, when you call +@post.save+ on an invalid +post, it will return +false+. If you open +app/controllers/posts_controller.rb+ +again, you'll notice that we don't check the result of calling +@post.save+ +inside the +create+ action. If +@post.save+ fails in this situation, we need to +show the form back to the user. To do this, change the +new+ and +create+ +actions inside +app/controllers/posts_controller.rb+ to these: <ruby> def new @@ -704,13 +723,11 @@ def create end </ruby> -Notice that I've also added +@post = Post.new+ to the +new+ action. I'll -explain why I did that in the next section, for now add that to your -controller as well. +The +new+ action is now creating a new instance variable called +@post+, and +you'll see why that is in just a few moments. -Also notice that we use +render+ instead of +redirect_to+ when +save+ -returns false. We can use +render+ so that the +@post+ object is passed -back to the view. +Notice that inside the +create+ action we use +render+ instead of +redirect_to+ when +save+ +returns +false+. The +render+ method is used so that the +@post+ object is passed back to the +new+ template when it is rendered. This rendering is done within the same request as the form submission, whereas the +redirect_to+ will tell the browser to issue another request. If you reload "http://localhost:3000/posts/new":http://localhost:3000/posts/new and @@ -754,9 +771,8 @@ A few things are going on. We check if there are any errors with +@post.errors.any?+, and in that case we show a list of all errors with +@post.errors.full_messages+. -+pluralize+ is a rails helper -that takes a number and a string as its arguments. If the number is -greater than one, the string will be automatically pluralized. ++pluralize+ is a rails helper that takes a number and a string as its +arguments. If the number is greater than one, the string will be automatically pluralized. The reason why we added +@post = Post.new+ in +posts_controller+ is that otherwise +@post+ would be +nil+ in our view, and calling @@ -766,7 +782,8 @@ TIP: Rails automatically wraps fields that contain an error with a div with class +field_with_errors+. You can define a css rule to make them standout. -Now you'll get a nice error message when saving a post without title: +Now you'll get a nice error message when saving a post without title when you +attempt to do just that on the "new post form(http://localhost:3000/posts/new)":http://localhost:3000/posts/new. !images/getting_started/form_with_errors.png(Form With Errors)! @@ -830,21 +847,23 @@ it look as follows: <%= link_to 'Back', :action => :index %> </erb> -This time we point the form to the +update+ action (not defined yet). +This time we point the form to the +update+ action, which is not defined yet +but will be very soon. + The +:method => :put+ option tells Rails that we want this form to be -submitted via +put+, which is the http method you're expected to use to +submitted via the +PUT+, HTTP method which is the HTTP method you're expected to use to *update* resources according to the REST protocol. TIP: By default forms built with the +form_for_ helper are sent via +POST+. -Moving on, we need to add the +update+ action. The file +Next, we need to add the +update+ action. The file +config/routes.rb+ will need just one more line: <ruby> put "posts/:id" => "posts#update" </ruby> -And the +update+ action in +posts_controller+ itself should not look too complicated by now: +And then create the +update+ action in +app/controllers/posts_controller.rb+: <ruby> def update @@ -858,7 +877,7 @@ def update end </ruby> -The new method +update_attributes+ is used when you want to update a record +The new method, +update_attributes+, is used when you want to update a record that already exists, and it accepts an hash containing the attributes that you want to update. As before, if there was an error updating the post we want to show the form back to the user. @@ -868,11 +887,11 @@ example, if you'd call +@post.update_attributes(:title => 'A new title')+ Rails would only update the +title+ attribute, leaving all other attributes untouched. -Finally, we want to show a link to the +edit+ action in the +index+ and -+show+ views: +Finally, we want to show a link to the +edit+ action in the list of all the +posts, so let's add that now to +app/views/posts/index.html.erb+ to make it +appear next to the "Show" link: <erb> -# app/view/posts/index.html.erb <table> <tr> @@ -891,11 +910,16 @@ Finally, we want to show a link to the +edit+ action in the +index+ and </tr> <% end %> </table> +</erb> -# app/view/posts/show.html.erb +And we'll also add one to the +app/views/posts/show.html.erb+ template as well, +so that there's also an "Edit" link on a post's page. Add this at the bottom of +the template: +<erb> ... + <%= link_to 'Back', :action => :index %> | <%= link_to 'Edit', :action => :edit, :id => @post.id %> </erb> @@ -924,8 +948,8 @@ simple example: <%= @user.about_me %> </erb> -The +show+ view will automatically include the content of the -+_user_details+ view. Note that partials are prefixed by an underscore, +The +users/show+ template will automatically include the content of the ++users/_user_details+ template. Note that partials are prefixed by an underscore, as to not be confused with regular views. However, you don't include the underscore when including them with the +helper+ method. @@ -934,7 +958,7 @@ Rails":layouts_and_rendering.html guide. Our +edit+ action looks very similar to the +new+ action, in fact they both share the same code for displaying the form. Lets clean them up by -using a +_form+ partial. +using a partial. Create a new file +app/views/posts/_form.html.erb+ with the following content: @@ -944,7 +968,7 @@ content: <% if @post.errors.any? %> <div id="errorExplanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited - this post from being saved:</h2> + this post from being saved:</h2> <ul> <% @post.errors.full_messages.each do |msg| %> <li><%= msg %></li> @@ -968,23 +992,23 @@ content: <% end %> </erb> -Everything except for the +form_for+ declaration remained the same. I'll -explain later how +form_for+ can figure out the right +action+ and -+method+ attributes when building the form, for now let's update the -+new+ and +edit+ views: +Everything except for the +form_for+ declaration remained the same. +How +form_for+ can figure out the right +action+ and +method+ attributes +when building the form will be explained in just a moment. For now, let's update the ++app/views/posts/new.html.erb+ view to use this new partial, rewriting it +completely: <erb> -# app/views/posts/new.html.erb - <h1>New post</h1> <%= render 'form' %> <%= link_to 'Back', :action => :index %> +</erb> +Then do the same for the +app/views/posts/edit.html.erb+ view: -# app/views/posts/edit.html.erb - +<erb> <h1>Edit post</h1> <%= render 'form' %> @@ -992,8 +1016,7 @@ explain later how +form_for+ can figure out the right +action+ and <%= link_to 'Back', :action => :index %> </erb> -Point your browser to -"http://localhost:3000/posts/new":http://localhost:3000/posts/new and +Point your browser to "http://localhost:3000/posts/new":http://localhost:3000/posts/new and try creating a new post. Everything still works. Now try editing the post and you'll receive the following error: @@ -1011,7 +1034,8 @@ knows that it should create new objects via POST and update them via PUT. If you run +rake routes+ from the console you'll see that we already -have a +posts_path+ route, which was created automatically by Rails. +have a +posts_path+ route, which was created automatically by Rails when we +defined the route for the index action. However, we don't have a +post_path+ yet, which is the reason why we received an error before. @@ -1034,26 +1058,37 @@ line like this: get "posts/:id" => "posts#show", :as => :post </ruby> -Now you'll be able to update posts again. +The +:as+ option tells the +get+ method that we want to make routing helpers +called +post_url+ and +post_path+ available to our application. These are +precisely the methods that the +form_for+ needs when editing a post, and so now +you'll be able to update posts again. + +NOTE: The +:as+ option is available on the +post+, +put+, +delete+ and +match+ +routing methods also. h4. Deleting Posts We're now ready to cover the "D" part of CRUD, deleting posts from the database. Following the REST convention, we're going to add a route for -deleting posts: +deleting posts to +config/routes.rb+: <ruby> -# config/routes.rb - delete "posts/:id" => "posts#destroy" </ruby> -We use the +delete+ method for destroying resources, which is mapped to -the +destroy+ action, which is provided below: +The +delete+ routing method should be used for routes that destroy +resources. If this was left as a typical +get+ route, it could be possible for +people to craft malicious URLs like this: -<ruby> -# app/controllers/posts_controller.rb +<html> +<a href='http://yoursite.com/posts/1/destroy'>look at this cat!</a> +</html> +We use the +delete+ method for destroying resources, and this route is mapped to +the +destroy+ action inside +app/controllers/posts_controller.rb+, which doesn't exist yet, but is +provided below: + +<ruby> def destroy @post = Post.find(params[:id]) @post.destroy @@ -1063,13 +1098,15 @@ end </ruby> You can call +destroy+ on Active Record objects when you want to delete -them from the dabase. Note that we don't need to add a view for this +them from the database. Note that we don't need to add a view for this action since we're redirecting to the +index+ action. -Finally, add a 'destroy' link to your +index+ action to wrap everything +Finally, add a 'destroy' link to your +index+ action template +(+app/views/posts/index.html.erb) to wrap everything together. <erb> +<h1>Listing Posts</h1> <table> <tr> <th>Title</th> @@ -1092,11 +1129,14 @@ together. </erb> Here we're using +link_to+ in a different way. We wrap the -+:action+ and +:id+ attributes in a hash so that we can pass other -arguments to +link_to+. The +:method+ and +:confirm+ ++:action+ and +:id+ attributes in a hash so that we can pass those two keys in +first as one argument, and then the final two keys as another argument. The +:method+ and +:confirm+ options are used as html5 attributes so that when the click is linked, Rails will first show a confirm dialog to the user, and then submit the -link with method +delete+. This is done via javascript automatically. +link with method +delete+. This is done via the JavaScript file +jquery_ujs+ +which is automatically included into your application's layout +(+app/views/layouts/application.html.erb+) when you generated the application. +Without this file, the confirmation dialog box wouldn't appear. !images/getting_started/confirm_dialog.png(Confirm Dialog)! @@ -1136,7 +1176,7 @@ end </ruby> If you run +rake routes+, you'll see that all the routes that we -declared before are still available, and the app still works as before. +declared before are still available: <shell> # rake routes @@ -1150,18 +1190,22 @@ edit_post GET /posts/:id/edit(.:format) posts#edit root / welcome#index </shell> +Also, if you go through the motions of creating, updating and deleting +posts the app still works as before. + TIP: In general, Rails encourages the use of resources objects in place -of declaring routes manually. For more information about routing, see +of declaring routes manually. It was only done in this guide as a learning +exercise. For more information about routing, see "Rails Routing from the Outside In":routing.html. h3. Adding a Second Model It's time to add a second model to the application. The second model will handle comments on -blog posts. +posts. h4. Generating a Model -We're going to se the same generator that we used before when creating +We're going to see the same generator that we used before when creating the +Post+ model. This time we'll create a +Comment+ model to hold reference of post comments. Run this command in your terminal: @@ -1321,7 +1365,7 @@ So first, we'll wire up the Post show template <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Add a comment:</h2> @@ -1344,7 +1388,10 @@ So first, we'll wire up the Post show template </erb> This adds a form on the +Post+ show page that creates a new comment by -calling the +CommentsController+ +create+ action. Let's wire that up: +calling the +CommentsController+ +create+ action. The +form_for+ call here uses +an array, which will build a nested route, such as +/posts/1/comments+. + +Let's wire up the +create+: <ruby> class CommentsController < ApplicationController @@ -1380,7 +1427,7 @@ template. This is where we want the comment to show, so let's add that to the <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Comments</h2> @@ -1428,7 +1475,7 @@ use partials to clean it up. h4. Rendering Partial Collections -First we will make a comment partial to extract showing all the comments for the +First, we will make a comment partial to extract showing all the comments for the post. Create the file +app/views/comments/_comment.html.erb+ and put the following into it: @@ -1455,7 +1502,7 @@ following: <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Comments</h2> @@ -1517,7 +1564,7 @@ Then you make the +app/views/posts/show.html.erb+ look like the following: <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Add a comment:</h2> diff --git a/guides/source/i18n.textile b/guides/source/i18n.textile index 6179694c40..ee7176a6c8 100644 --- a/guides/source/i18n.textile +++ b/guides/source/i18n.textile @@ -127,7 +127,7 @@ If you want to translate your Rails application to a *single language other than However, you would probably like to *provide support for more locales* in your application. In such case, you need to set and pass the locale between requests. -WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>. *Do not do so*. The locale should be transparent and a part of the URL. This way you don't break people's basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you're being "<em>RESTful</em>":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. There may be some exceptions to this rule, which are discussed below. +WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>, however *do not do this*. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being "<em>RESTful</em>":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. Sometimes there are exceptions to this rule and those are discussed below. The _setting part_ is easy. You can set the locale in a +before_filter+ in the +ApplicationController+ like this: @@ -220,7 +220,7 @@ Every helper method dependent on +url_for+ (e.g. helpers for named routes like + You may be satisfied with this. It does impact the readability of URLs, though, when the locale "hangs" at the end of every URL in your application. Moreover, from the architectural standpoint, locale is usually hierarchically above the other parts of the application domain: and URLs should reflect this. -You probably want URLs to look like this: +www.example.com/en/books+ (which loads the English locale) and +www.example.com/nl/books+ (which loads the Netherlands locale). This is achievable with the "over-riding +default_url_options+" strategy from above: you just have to set up your routes with "+path_prefix+":http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354 option in this way: +You probably want URLs to look like this: +www.example.com/en/books+ (which loads the English locale) and +www.example.com/nl/books+ (which loads the Dutch locale). This is achievable with the "over-riding +default_url_options+" strategy from above: you just have to set up your routes with "+path_prefix+":http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354 option in this way: <ruby> # config/routes.rb @@ -229,7 +229,7 @@ scope "/:locale" do end </ruby> -Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Netherlands locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed). +Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Dutch locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed). If you don't want to force the use of a locale in your routes you can use an optional path scope (denoted by the parentheses) like so: diff --git a/guides/source/layouts_and_rendering.textile b/guides/source/layouts_and_rendering.textile index e4a1fd6951..b0a87a5981 100644 --- a/guides/source/layouts_and_rendering.textile +++ b/guides/source/layouts_and_rendering.textile @@ -860,12 +860,6 @@ You can supply a hash of additional HTML options: <%= image_tag "icons/delete.gif", {:height => 45} %> </erb> -You can also supply an alternate image to show on mouseover: - -<erb> -<%= image_tag "home.gif", :onmouseover => "menu/home_highlight.gif" %> -</erb> - You can supply alternate text for the image which will be used if the user has images turned off in their browser. If you do not specify an alt text explicitly, it defaults to the file name of the file, capitalized and with no extension. For example, these two image tags would return the same code: <erb> diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile index f855072fd8..52dba76e68 100644 --- a/guides/source/migrations.textile +++ b/guides/source/migrations.textile @@ -737,9 +737,7 @@ column. class AddFlagToProduct < ActiveRecord::Migration def change add_column :products, :flag, :boolean - Product.all.each do |product| - product.update_attributes!(:flag => false) - end + Product.update_all :flag => false end end </ruby> @@ -762,9 +760,7 @@ column. class AddFuzzToProduct < ActiveRecord::Migration def change add_column :products, :fuzz, :string - Product.all.each do |product| - product.update_attributes! :fuzz => 'fuzzy' - end + Product.update_all :fuzz => 'fuzzy' end end </ruby> @@ -816,9 +812,7 @@ class AddFlagToProduct < ActiveRecord::Migration def change add_column :products, :flag, :boolean Product.reset_column_information - Product.all.each do |product| - product.update_attributes!(:flag => false) - end + Product.update_all :flag => false end end </ruby> @@ -833,9 +827,7 @@ class AddFuzzToProduct < ActiveRecord::Migration def change add_column :products, :fuzz, :string Product.reset_column_information - Product.all.each do |product| - product.update_attributes!(:fuzz => 'fuzzy') - end + Product.update_all :fuzz => 'fuzzy' end end </ruby> |