From 8ff7693a8dc61f43fc4eaf72ed24d3b8699191fe Mon Sep 17 00:00:00 2001 From: Jose and Yehuda Date: Mon, 26 Sep 2011 18:48:19 -0400 Subject: Initial commit of serializer support --- railties/guides/source/serializers.textile | 600 +++++++++++++++++++++++++++++ 1 file changed, 600 insertions(+) create mode 100644 railties/guides/source/serializers.textile (limited to 'railties/guides') diff --git a/railties/guides/source/serializers.textile b/railties/guides/source/serializers.textile new file mode 100644 index 0000000000..a631a14694 --- /dev/null +++ b/railties/guides/source/serializers.textile @@ -0,0 +1,600 @@ +h2. Rails Serializers + +This guide describes how to use Active Model serializers to build non-trivial JSON services in Rails. By reading this guide, you will learn: + +* When to use the built-in Active Model serialization +* When to use a custom serializer for your models +* How to use serializers to encapsulate authorization concerns +* How to create serializer templates to describe the application-wide structure of your serialized JSON +* How to build resources not backed by a single database table for use with JSON services + +This guide covers an intermediate topic and assumes familiarity with Rails conventions. It is suitable for applications that expose a +JSON API that may return different results based on the authorization status of the user. + +endprologue. + +h3. Serialization + +By default, Active Record objects can serialize themselves into JSON by using the `to_json` method. This method takes a series of additional +parameter to control which properties and associations Rails should include in the serialized output. + +When building a web application that uses JavaScript to retrieve JSON data from the server, this mechanism has historically been the primary +way that Rails developers prepared their responses. This works great for simple cases, as the logic for serializing an Active Record object +is neatly encapsulated in Active Record itself. + +However, this solution quickly falls apart in the face of serialization requirements based on authorization. For instance, a web service +may choose to expose additional information about a resource only if the user is entitled to access it. In addition, a JavaScript front-end +may want information that is not neatly described in terms of serializing a single Active Record object, or in a different format than. + +In addition, neither the controller nor the model seems like the correct place for logic that describes how to serialize an model object +*for the current user*. + +Serializers solve these problems by encapsulating serialization in an object designed for this purpose. If the default +to_json+ semantics, +with at most a few configuration options serve your needs, by all means continue to use the built-in +to_json+. If you find yourself doing +hash-driven-development in your controllers, juggling authorization logic and other concerns, serializers are for you! + +h3. The Most Basic Serializer + +A basic serializer is a simple Ruby object named after the model class it is serializing. + + +class PostSerializer + def initialize(post, scope) + @post, @scope = post, scope + end + + def as_json + { post: { title: @post.name, body: @post.body } } + end +end + + +A serializer is initialized with two parameters: the model object it should serialize and an authorization scope. By default, the +authorization scope is the current user (+current_user+) but you can use a different object if you want. The serializer also +implements an +as_json+ method, which returns a Hash that will be sent to the JSON encoder. + +Rails will transparently use your serializer when you use +render :json+ in your controller. + + +class PostsController < ApplicationController + def show + @post = Post.find(params[:id]) + render json: @post + end +end + + +Because +respond_with+ uses +render :json+ under the hood for JSON requests, Rails will automatically use your serializer when +you use +respond_with+ as well. + +h4. +serializable_hash+ + +In general, you will want to implement +serializable_hash+ and +as_json+ to allow serializers to embed associated content +directly. The easiest way to implement these two methods is to have +as_json+ call +serializable_hash+ and insert the root. + + +class PostSerializer + def initialize(post, scope) + @post, @scope = post, scope + end + + def serializable_hash + { title: @post.name, body: @post.body } + end + + def as_json + { post: serializable_hash } + end +end + + +h4. Authorization + +Let's update our serializer to include the email address of the author of the post, but only if the current user has superuser +access. + + +class PostSerializer + def initialize(post, scope) + @post, @scope = post, scope + end + + def as_json + { post: serializable_hash } + end + + def serializable_hash + hash = post + hash.merge!(super_data) if super? + hash + end + +private + def post + { title: @post.name, body: @post.body } + end + + def super_data + { email: @post.email } + end + + def super? + @scope.superuser? + end +end + + +h4. Testing + +One benefit of encapsulating our objects this way is that it becomes extremely straight-forward to test the serialization +logic in isolation. + + +require "ostruct" + +class PostSerializerTest < ActiveSupport::TestCase + # For now, we use a very simple authorization structure. These tests will need + # refactoring if we change that. + plebe = OpenStruct.new(super?: false) + god = OpenStruct.new(super?: true) + + post = OpenStruct.new(title: "Welcome to my blog!", body: "Blah blah blah", email: "tenderlove@gmail.com") + + test "a regular user sees just the title and body" do + json = PostSerializer.new(post, plebe).to_json + hash = JSON.parse(json) + + assert_equal post.title, hash.delete("title") + assert_equal post.body, hash.delete("body") + assert_empty hash + end + + test "a superuser sees the title, body and email" do + json = PostSerializer.new(post, god).to_json + hash = JSON.parse(json) + + assert_equal post.title, hash["title"] + assert_equal post.body, hash["body"] + assert_equal post.email, hash["email"] + assert_empty hash + end +end + + +It's important to note that serializer objects define a clear interface specifically for serializing an existing object. +In this case, the serializer expects to receive a post object with +name+, +body+ and +email+ attributes and an authorization +scope with a +super?+ method. + +By defining a clear interface, it's must easier to ensure that your authorization logic is behaving correctly. In this case, +the serializer doesn't need to concern itself with how the authorization scope decides whether to set the +super?+ flag, just +whether it is set. In general, you should document these requirements in your serializer files and programatically via tests. +The documentation library +YARD+ provides excellent tools for describing this kind of requirement: + + +class PostSerializer + # @param [~body, ~title, ~email] post the post to serialize + # @param [~super] scope the authorization scope for this serializer + def initialize(post, scope) + @post, @scope = post, scope + end + + # ... +end + + +h3. Attribute Sugar + +To simplify this process for a number of common cases, Rails provides a default superclass named +ActiveModel::Serializer+ +that you can use to implement your serializers. + +For example, you will sometimes want to simply include a number of existing attributes from the source model into the outputted +JSON. In the above example, the +title+ and +body+ attributes were always included in the JSON. Let's see how to use ++ActiveModel::Serializer+ to simplify our post serializer. + + +class PostSerializer < ActiveModel::Serializer + attributes :title, :body + + def initialize(post, scope) + @post, @scope = post, scope + end + + def serializable_hash + hash = attributes + hash.merge!(super_data) if super? + hash + end + +private + def super_data + { email: @post.email } + end + + def super? + @scope.superuser? + end +end + + +First, we specified the list of included attributes at the top of the class. This will create an instance method called ++attributes+ that extracts those attributes from the post model. + +NOTE: Internally, +ActiveModel::Serializer+ uses +read_attribute_for_serialization+, which defaults to +read_attribute+, which defaults to +send+. So if you're rolling your own models for use with the serializer, you can use simple Ruby accessors for your attributes if you like. + +Next, we use the attributes methood in our +serializable_hash+ method, which allowed us to eliminate the +post+ method we hand-rolled +earlier. We could also eliminate the +as_json+ method, as +ActiveModel::Serializer+ provides a default +as_json+ method for +us that calls our +serializable_hash+ method and inserts a root. But we can go a step further! + + +class PostSerializer < ActiveModel::Serializer + attributes :title, :body + +private + def attributes + hash = super + hash.merge!(email: post.email) if super? + hash + end + + def super? + @scope.superuser? + end +end + + +The superclass provides a default +initialize+ method as well as a default +serializable_hash+ method, which uses ++attributes+. We can call +super+ to get the hash based on the attributes we declared, and then add in any additional +attributes we want to use. + +NOTE: +ActiveModel::Serializer+ will create an accessor matching the name of the current class for the resource you pass in. In this case, because we have defined a PostSerializer, we can access the resource with the +post+ accessor. + +h3. Associations + +In most JSON APIs, you will want to include associated objects with your serialized object. In this case, let's include +the comments with the current post. + + +class PostSerializer < ActiveModel::Serializer + attributes :title. :body + has_many :comments + +private + def attributes + hash = super + hash.merge!(email: post.email) if super? + hash + end + + def super? + @scope.superuser? + end +end + + +The default +serializable_hash+ method will include the comments as embedded objects inside the post. + + +{ + post: { + title: "Hello Blog!", + body: "This is my first post. Isn't it fabulous!", + comments: [ + { + title: "Awesome", + body: "Your first post is great" + } + ] + } +} + + +Rails uses the same logic to generate embedded serializations as it does when you use +render :json+. In this case, +because you didn't define a +CommentSerializer+, Rails used the default +as_json+ on your comment object. + +If you define a serializer, Rails will automatically instantiate it with the existing authorization scope. + + +class CommentSerializer + def initialize(comment, scope) + @comment, @scope = comment, scope + end + + def serializable_hash + { title: @comment.title } + end + + def as_json + { comment: serializable_hash } + end +end + + +If we define the above comment serializer, the outputted JSON will change to: + + +{ + post: { + title: "Hello Blog!", + body: "This is my first post. Isn't it fabulous!", + comments: [{ title: "Awesome" }] + } +} + + +Let's imagine that our comment system allows an administrator to kill a comment, and we only want to allow +users to see the comments they're entitled to see. By default, +has_many :comments+ will simply use the ++comments+ accessor on the post object. We can override the +comments+ accessor to limit the comments used +to just the comments we want to allow for the current user. + + +class PostSerializer < ActiveModel::Serializer + attributes :title. :body + has_many :comments + +private + def attributes + hash = super + hash.merge!(email: post.email) if super? + hash + end + + def comments + post.comments_for(scope) + end + + def super? + @scope.superuser? + end +end + + ++ActiveModel::Serializer+ will still embed the comments, but this time it will use just the comments +for the current user. + +NOTE: The logic for deciding which comments a user should see still belongs in the model layer. In general, you should encapsulate concerns that require making direct Active Record queries in scopes or public methods on your models. + +h3. Customizing Associations + +Not all front-ends expect embedded documents in the same form. In these cases, you can override the +default +serializable_hash+, and use conveniences provided by +ActiveModel::Serializer+ to avoid having to +build up the hash manually. + +For example, let's say our front-end expects the posts and comments in the following format: + + +{ + post: { + id: 1 + title: "Hello Blog!", + body: "This is my first post. Isn't it fabulous!", + comments: [1,2] + }, + comments: [ + { + id: 1 + title: "Awesome", + body: "Your first post is great" + }, + { + id: 2 + title: "Not so awesome", + body: "Why is it so short!" + } + ] +} + + +We could achieve this with a custom +as_json+ method. We will also need to define a serializer for comments. + + +class CommentSerializer < ActiveModel::Serializer + attributes :id, :title, :body + + # define any logic for dealing with authorization-based attributes here +end + +class PostSerializer < ActiveModel::Serializer + attributes :title. :body + has_many :comments + + def as_json + { post: serializable_hash }.merge!(associations) + end + + def serializable_hash + post_hash = attributes + post_hash.merge!(association_ids) + post_hash + end + +private + def attributes + hash = super + hash.merge!(email: post.email) if super? + hash + end + + def comments + post.comments_for(scope) + end + + def super? + @scope.superuser? + end +end + + +Here, we used two convenience methods: +associations+ and +association_ids+. The first, ++associations+, creates a hash of all of the define associations, using their defined +serializers. The second, +association_ids+, generates a hash whose key is the association +name and whose value is an Array of the association's keys. + +The +association_ids+ helper will use the overridden version of the association, so in +this case, +association_ids+ will only include the ids of the comments provided by the ++comments+ method. + +h3. Special Association Serializers + +So far, associations defined in serializers use either the +as_json+ method on the model +or the defined serializer for the association type. Sometimes, you may want to serialize +associated models differently when they are requested as part of another resource than +when they are requested on their own. + +For instance, we might want to provide the full comment when it is requested directly, +but only its title when requested as part of the post. To achieve this, you can define +a serializer for associated objects nested inside the main serializer. + + +class PostSerializer < ActiveModel::Serializer + class CommentSerializer < ActiveModel::Serializer + attributes :id, :title + end + + # same as before + # ... +end + + +In other words, if a +PostSerializer+ is trying to serialize comments, it will first +look for +PostSerializer::CommentSerializer+ before falling back to +CommentSerializer+ +and finally +comment.as_json+. + +h3. Optional Associations + +In some cases, you will want to allow a front-end to decide whether to include associated +content or not. You can achieve this easily by making an association *optional*. + + +class PostSerializer < ActiveModel::Serializer + attributes :title. :body + has_many :comments, :optional => true + + # ... +end + + +If an association is optional, it will not be included unless the request asks for it +with an +including+ parameter. The +including+ parameter is a comma-separated list of +optional associations to include. If the +including+ parameter includes an association +you did not specify in your serializer, it will receive a +401 Forbidden+ response. + +h3. Overriding the Defaults + +h4. Authorization Scope + +By default, the authorization scope for serializers is +:current_user+. This means +that when you call +render json: @post+, the controller will automatically call +its +current_user+ method and pass that along to the serializer's initializer. + +If you want to change that behavior, simply use the +serialization_scope+ class +method. + + +class PostsController < ApplicationController + serialization_scope :current_app +end + + +You can also implement an instance method called (no surprise) +serialization_scope+, +which allows you to define a dynamic authorization scope based on the current request. + +WARNING: If you use different objects as authorization scopes, make sure that they all implement whatever interface you use in your serializers to control what the outputted JSON looks like. + +h4. Parameter to Specify Included Optional Associations + +In most cases, you should be able to use the default +including+ parameter to specify +which optional associations to include. If you are already using that parameter name or +want to reserve it for some reason, you can specify a different name by using the ++serialization_includes_param+ class method. + + +class PostsController < ApplicationController + serialization_includes_param :associations_to_include +end + + +You can also implement a +serialization_includes+ instance method, which should return an +Array of optional includes. + +WARNING: If you implement +serialization_includes+ and return an invalid association, your user will receive a +401 Forbidden+ exception. + +h3. Using Serializers Outside of a Request + +The serialization API encapsulates the concern of generating a JSON representation of +a particular model for a particular user. As a result, you should be able to easily use +serializers, whether you define them yourself or whether you use +ActiveModel::Serializer+ +outside a request. + +For instance, if you want to generate the JSON representation of a post for a user outside +of a request: + + +user = get_user # some logic to get the user in question +PostSerializer.new(post, user).to_json # reliably generate JSON output + + +If you want to generate JSON for an anonymous user, you should be able to use whatever +technique you use in your application to generate anonymous users outside of a request. +Typically, that means creating a new user and not saving it to the database: + + +user = User.new # create a new anonymous user +PostSerializer.new(post, user).to_json + + +In general, the better you encapsulate your authorization logic, the more easily you +will be able to use the serializer outside of the context of a request. For instance, +if you use an authorization library like Cancan, which uses a uniform +user.can?(action, model)+, +the authorization interface can very easily be replaced by a plain Ruby object for +testing or usage outside the context of a request. + +h3. Collections + +So far, we've talked about serializing individual model objects. By default, Rails +will serialize collections, including when using the +associations+ helper, by +looping over each element of the collection, calling +serializable_hash+ on the element, +and then grouping them by their type (using the plural version of their class name +as the root). + +For example, an Array of post objects would serialize as: + + +{ + posts: [ + { + title: "FIRST POST!", + body: "It's my first pooooost" + }, + { title: "Second post!", + body: "Zomg I made it to my second post" + } + ] +} + + +If you want to change the behavior of serialized Arrays, you need to create +a custom Array serializer. + + +class ArraySerializer < ActiveModel::ArraySerializer + def serializable_array + serializers.map do |serializer| + serializer.serializable_hash + end + end + + def as_json + hash = { root => serializable_array } + hash.merge!(associations) + hash + end +end + + +When generating embedded associations using the +associations+ helper inside a +regular serializer, it will create a new ArraySerializer with the +associated content and call its +serializable_array+ method. In this case, those +embedded associations will not recursively include associations. + +When generating an Array using +render json: posts+, the controller will invoke +the +as_json+ method, which will include its associations and its root. -- cgit v1.2.3 From f5836543c3cd16f7789c936a4181f4a7204141dc Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 28 Sep 2011 17:05:03 +0530 Subject: minor edits in serializers guide --- railties/guides/source/serializers.textile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/serializers.textile b/railties/guides/source/serializers.textile index a631a14694..86a5e5ac8d 100644 --- a/railties/guides/source/serializers.textile +++ b/railties/guides/source/serializers.textile @@ -153,9 +153,9 @@ class PostSerializerTest < ActiveSupport::TestCase json = PostSerializer.new(post, god).to_json hash = JSON.parse(json) - assert_equal post.title, hash["title"] - assert_equal post.body, hash["body"] - assert_equal post.email, hash["email"] + assert_equal post.title, hash.delete("title") + assert_equal post.body, hash.delete("body") + assert_equal post.email, hash.delete("email") assert_empty hash end end @@ -255,7 +255,7 @@ the comments with the current post. class PostSerializer < ActiveModel::Serializer - attributes :title. :body + attributes :title, :body has_many :comments private @@ -361,7 +361,7 @@ build up the hash manually. For example, let's say our front-end expects the posts and comments in the following format: - + { post: { id: 1 @@ -382,7 +382,7 @@ For example, let's say our front-end expects the posts and comments in the follo } ] } - + We could achieve this with a custom +as_json+ method. We will also need to define a serializer for comments. @@ -394,7 +394,7 @@ class CommentSerializer < ActiveModel::Serializer end class PostSerializer < ActiveModel::Serializer - attributes :title. :body + attributes :title, :body has_many :comments def as_json @@ -558,7 +558,7 @@ as the root). For example, an Array of post objects would serialize as: - + { posts: [ { @@ -570,7 +570,7 @@ For example, an Array of post objects would serialize as: } ] } - + If you want to change the behavior of serialized Arrays, you need to create a custom Array serializer. -- cgit v1.2.3 From bc00514b6236d701d3e660c4ec365a767a070a91 Mon Sep 17 00:00:00 2001 From: rpq Date: Tue, 15 Nov 2011 23:20:21 -0500 Subject: added comma --- railties/guides/source/asset_pipeline.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 6ff5e87b6d..3681501293 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -438,7 +438,7 @@ location ~ ^/assets/ { } -When files are precompiled, Sprockets also creates a "gzipped":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. Web servers are typically configured to use a moderate compression ratio as a compromise, but since precompilation happens once Sprockets uses the maximum compression ratio, thus reducing the size of the data transfer to the minimum. On the other hand, web servers can be configured to serve compressed content directly from disk, rather than deflating non-compressed files themselves. +When files are precompiled, Sprockets also creates a "gzipped":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. Web servers are typically configured to use a moderate compression ratio as a compromise, but since precompilation happens once, Sprockets uses the maximum compression ratio, thus reducing the size of the data transfer to the minimum. On the other hand, web servers can be configured to serve compressed content directly from disk, rather than deflating non-compressed files themselves. Nginx is able to do this automatically enabling +gzip_static+: -- cgit v1.2.3 From 64a3175eea3c121f30a5a24034aa1ed400c80b12 Mon Sep 17 00:00:00 2001 From: capps Date: Wed, 16 Nov 2011 15:57:54 -0800 Subject: "denoted" instead of "donated" "parentheses" instead of "use brackets" --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 2d4cc13571..e9477e84cf 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -231,7 +231,7 @@ end 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). -If you don't want to force the use of a locale in your routes you can use an optional path scope (donated by the use brackets) like so: +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: # config/routes.rb -- cgit v1.2.3 From 0af93089deaf6dc9428c0f2f7a376cdb6f81daee Mon Sep 17 00:00:00 2001 From: Alex Tambellini Date: Thu, 17 Nov 2011 09:44:17 -0500 Subject: Move schema_format :sql config setting from test.rb to application.rb I've moved the schema_format :sql config setting to application.rb because you would never enable this only for the test environment. If you use database constraints or database specific data types you would want all of your environments to use them. --- railties/guides/code/getting_started/config/application.rb | 5 +++++ railties/guides/code/getting_started/config/environments/test.rb | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/code/getting_started/config/application.rb b/railties/guides/code/getting_started/config/application.rb index e914b5a80e..e16da30f72 100644 --- a/railties/guides/code/getting_started/config/application.rb +++ b/railties/guides/code/getting_started/config/application.rb @@ -39,6 +39,11 @@ module Blog # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + # Enable the asset pipeline config.assets.enabled = true diff --git a/railties/guides/code/getting_started/config/environments/test.rb b/railties/guides/code/getting_started/config/environments/test.rb index 833241ace3..08697cbbc9 100644 --- a/railties/guides/code/getting_started/config/environments/test.rb +++ b/railties/guides/code/getting_started/config/environments/test.rb @@ -29,11 +29,6 @@ Blog::Application.configure do # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Use SQL instead of Active Record's schema dumper when creating the test database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - # Print deprecation notices to the stderr config.active_support.deprecation = :stderr -- cgit v1.2.3 From 8d17af23ef5202e7c28bbf701e247bce6011df07 Mon Sep 17 00:00:00 2001 From: Sunny Ripert Date: Thu, 17 Nov 2011 17:05:53 +0100 Subject: Guides: better example to find the last sent email --- railties/guides/source/testing.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index 2341a3522c..5dbbe2c0f0 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -927,7 +927,7 @@ class UserControllerTest < ActionController::TestCase assert_difference 'ActionMailer::Base.deliveries.size', +1 do post :invite_friend, :email => 'friend@example.com' end - invite_email = ActionMailer::Base.deliveries.first + invite_email = ActionMailer::Base.deliveries.last assert_equal "You have been invited by me@example.com", invite_email.subject assert_equal 'friend@example.com', invite_email.to[0] -- cgit v1.2.3 From 9b534060bfafbf1db36e73bb3e538b8c412dcc54 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Fri, 18 Nov 2011 01:17:21 +0530 Subject: update guide: db:structure:dump produces structure.sql now --- railties/guides/source/migrations.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 23e36b39f9..5b52a93853 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -658,7 +658,7 @@ In many ways this is exactly what it is. This file is created by inspecting the There is however a trade-off: +db/schema.rb+ cannot express database specific items such as foreign key constraints, triggers, or stored procedures. While in a migration you can execute custom SQL statements, the schema dumper cannot reconstitute those statements from the database. 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+ Rake task) into +db/#{Rails.env}_structure.sql+. For example, for the PostgreSQL RDBMS, the +pg_dump+ utility is used. For MySQL, 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. +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+ Rake task) into +db/structure.sql+. For example, for the PostgreSQL RDBMS, the +pg_dump+ utility is used. For MySQL, 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. h4. Schema Dumps and Source Control -- cgit v1.2.3 From d57d8098fc269a26ea0051a9027a33af1a9a4b2b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 17 Nov 2011 23:07:06 +0100 Subject: warn the user values are directly interpolated into _html translation strings --- railties/guides/source/i18n.textile | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 2d4cc13571..43afa6c9e2 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -634,6 +634,18 @@ en: !images/i18n/demo_html_safe.png(i18n demo html safe)! +Please note that values are interpolated directly into the translation. +If they need to be escaped you need to pass them already escaped in the +t+ call. + + +# config/locales/en.yml +en: + welcome_html: Welcome %{name}! + +<%# Note the call to h() to avoid injection %> +<%= t('welcome_html', :name => h(user.name)) %> + + h3. How to Store your Custom Translations The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format. [2] -- cgit v1.2.3 From 1079724fe643fe63e6d58a37274c2cf0ff172a8b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 17 Nov 2011 23:59:19 +0100 Subject: Revert "warn the user values are directly interpolated into _html translation strings" Reason: After another round of discussion, it has been decided to let interpolation deal with unsafe strings as it should do. This reverts commit d57d8098fc269a26ea0051a9027a33af1a9a4b2b. --- railties/guides/source/i18n.textile | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 43afa6c9e2..2d4cc13571 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -634,18 +634,6 @@ en: !images/i18n/demo_html_safe.png(i18n demo html safe)! -Please note that values are interpolated directly into the translation. -If they need to be escaped you need to pass them already escaped in the +t+ call. - - -# config/locales/en.yml -en: - welcome_html: Welcome %{name}! - -<%# Note the call to h() to avoid injection %> -<%= t('welcome_html', :name => h(user.name)) %> - - h3. How to Store your Custom Translations The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format. [2] -- cgit v1.2.3 From 9d035292ba39fcb046656ceb28e7a2f10cdb7f9c Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Fri, 18 Nov 2011 23:10:12 +0530 Subject: remove unneeded params from issue tracker url --- railties/guides/source/contributing_to_ruby_on_rails.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile index 1cd70404a3..37ead2bff2 100644 --- a/railties/guides/source/contributing_to_ruby_on_rails.textile +++ b/railties/guides/source/contributing_to_ruby_on_rails.textile @@ -215,7 +215,7 @@ TIP: You may want to "put your git branch name in your shell prompt":http://qugs h3. Helping to Resolve Existing Issues -As a next step beyond reporting issues, you can help the core team resolve existing issues. If you check the "Everyone's Issues":https://github.com/rails/rails/issues?sort=created&direction=desc&state=open list in GitHub Issues, you'll find lots of issues already requiring attention. What can you do for these? Quite a bit, actually: +As a next step beyond reporting issues, you can help the core team resolve existing issues. If you check the "Everyone's Issues":https://github.com/rails/rails/issues list in GitHub Issues, you'll find lots of issues already requiring attention. What can you do for these? Quite a bit, actually: h4. Verifying Bug Reports -- cgit v1.2.3 From dda6787f44a4e9a90cc28b3efee5b63c7d8cd023 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 19 Nov 2011 00:07:50 +0530 Subject: mailer guide - update info about using default host. Fixes #3642 --- railties/guides/source/action_mailer_basics.textile | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index ad5b848d2c..26c95be031 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -362,21 +362,14 @@ When using named routes you only need to supply the +:host+: Email clients have no web context and so paths have no base URL to form complete web addresses. Thus, when using named routes only the "_url" variant makes sense. -It is also possible to set a default host that will be used in all mailers by setting the +:host+ option in the +ActionMailer::Base.default_url_options+ hash as follows: +It is also possible to set a default host that will be used in all mailers by setting the :host option as a configuration option in config/application.rb: -class UserMailer < ActionMailer::Base - default_url_options[:host] = "example.com" - - def welcome_email(user) - @user = user - @url = user_url(@user) - mail(:to => user.email, - :subject => "Welcome to My Awesome Site") - end -end +config.action_mailer.default_url_options = { :host => "example.com" } +If you use this setting, you should pass the :only_path => false option when using +url_for+. This will ensure that absolute URLs are generated because the +url_for+ view helper will, by default, generate relative URLs when a :host option isn't explicitly provided. + h4. Sending Multipart Emails Action Mailer will automatically send multipart emails if you have different templates for the same action. So, for our UserMailer example, if you have +welcome_email.text.erb+ and +welcome_email.html.erb+ in +app/views/user_mailer+, Action Mailer will automatically send a multipart email with the HTML and text versions setup as different parts. -- cgit v1.2.3 From ed5586fa9e2f585d2edeb600ab1c884e419f9f72 Mon Sep 17 00:00:00 2001 From: Matt Burke Date: Fri, 18 Nov 2011 14:10:17 -0500 Subject: Add config.active_record.identity_map to the configuration guide. --- railties/guides/source/configuring.textile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index cd6e7d116e..809948b41e 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -263,6 +263,8 @@ h4. Configuring Active Record * +config.active_record.whitelist_attributes+ will create an empty whitelist of attributes available for mass-assignment security for all models in your app. +* +config.active_record.identity_map+ controls whether the identity map is enabled, and is false by default. + The MySQL adapter adds one additional configuration option: * +ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans+ controls whether Active Record will consider all +tinyint(1)+ columns in a MySQL database to be booleans and is true by default. -- cgit v1.2.3 From 6b4939c3fd22924ee3d906f08fe739d848f80a3d Mon Sep 17 00:00:00 2001 From: James Dean Shepherd Date: Sun, 20 Nov 2011 02:34:55 +0000 Subject: Added links to the 'Rails Initialization Guide', marked as a work in progress --- railties/guides/source/index.html.erb | 4 ++++ railties/guides/source/layout.html.erb | 1 + 2 files changed, 5 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index c9a8c4fa5c..a8e12174ed 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -134,6 +134,10 @@ Ruby on Rails Guides <%= guide('Asset Pipeline', 'asset_pipeline.html') do %>

This guide documents the asset pipeline.

<% end %> + +<%= guide('The Rails Initialization Process', 'initialization.html', :work_in_progress => true) do %> +

This guide explains the internals of the Rails initialization process as of Rails 3.1

+<% end %>

Extending Rails

diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index 4c979888b7..83a17988ab 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -72,6 +72,7 @@
Rails Command Line Tools and Rake Tasks
Caching with Rails
Asset Pipeline
+
Rails Initialization Process
Extending Rails
The Basics of Creating Rails Plugins
-- cgit v1.2.3 From 5660a16d56bb738979c47bf3dea16a40c2547b16 Mon Sep 17 00:00:00 2001 From: James Dean Shepherd Date: Sun, 20 Nov 2011 02:36:50 +0000 Subject: Minor grammar, typo & readability fixes for beginning of Rails Initialization guide --- railties/guides/source/initialization.textile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 036b356a37..5ae9cf0f2b 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -17,7 +17,7 @@ As of Rails 3, +script/server+ has become +rails server+. This was done to centr h4. +bin/rails+ -The actual +rails+ command is kept in _bin/rails_ at the and goes like this: +The actual +rails+ command is kept in _bin/rails_: #!/usr/bin/env ruby @@ -31,7 +31,7 @@ rescue LoadError end -This file will attempt to load +rails/cli+ and if it cannot find it then add the +railties/lib+ path to the load path (+$:+) and will then try to require it again. +This file will attempt to load +rails/cli+. If it cannot find it then +railties/lib+ is added to the load path (+$:+) before retrying. h4. +railties/lib/rails/cli.rb+ @@ -56,7 +56,7 @@ else end
-The +rbconfig+ file here is out of Ruby's standard library and provides us with the +RbConfig+ class which contains useful information dependent on how Ruby was compiled. We'll see this in use in +railties/lib/rails/script_rails_loader+. +The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see this in use in +railties/lib/rails/script_rails_loader+. require 'pathname' @@ -71,7 +71,7 @@ module Rails end -The +rails/script_rails_loader+ file uses +RbConfig::Config+ to gather up the +bin_dir+ and +ruby_install_name+ values for the configuration which will result in a path such as +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby+, which is the default path on Mac OS X. If you're running Windows the path may be something such as +C:/Ruby192/bin/ruby+. Anyway, the path on your system may be different, but the point of this is that it will point at the known ruby executable location for your install. The +RbConfig::CONFIG["EXEEXT"]+ will suffix this path with ".exe" if the script is running on Windows. This constant is used later on in +exec_script_rails!+. As for the +SCRIPT_RAILS+ constant, we'll see that when we get to the +in_rails_application?+ method. +The +rails/script_rails_loader+ file uses +RbConfig::Config+ to obtain the +bin_dir+ and +ruby_install_name+ values for the configuration which together form the path to the Ruby interpreter. The +RbConfig::CONFIG["EXEEXT"]+ will suffix this path with ".exe" if the script is running on Windows. This constant is used later on in +exec_script_rails!+. As for the +SCRIPT_RAILS+ constant, we'll see that when we get to the +in_rails_application?+ method. Back in +rails/cli+, the next line is this: @@ -79,7 +79,7 @@ Back in +rails/cli+, the next line is this: Rails::ScriptRailsLoader.exec_script_rails!
-This method is defined in +rails/script_rails_loader+ like this: +This method is defined in +rails/script_rails_loader+: def self.exec_script_rails! @@ -96,7 +96,7 @@ rescue SystemCallError end -This method will first check if the current working directory (+cwd+) is a Rails application or is a subdirectory of one. The way to determine this is defined in the +in_rails_application?+ method like this: +This method will first check if the current working directory (+cwd+) is a Rails application or a subdirectory of one. This is determined by the +in_rails_application?+ method: def self.in_rails_application? @@ -104,7 +104,7 @@ def self.in_rails_application? end -The +SCRIPT_RAILS+ constant defined earlier is used here, with +File.exists?+ checking for its presence in the current directory. If this method returns +false+, then +in_rails_application_subdirectory?+ will be used: +The +SCRIPT_RAILS+ constant defined earlier is used here, with +File.exists?+ checking for its presence in the current directory. If this method returns +false+ then +in_rails_application_subdirectory?+ will be used: def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd)) @@ -112,17 +112,17 @@ def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd)) end -This climbs the directory tree until it reaches a path which contains a +script/rails+ file. If a directory is reached which contains this file then this line will run: +This climbs the directory tree until it reaches a path which contains a +script/rails+ file. If a directory containing this file is reached then this line will run: exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application? -This is effectively the same as doing +ruby script/rails [arguments]+. Where +[arguments]+ at this point in time is simply "server". +This is effectively the same as running +ruby script/rails [arguments]+, where +[arguments]+ at this point in time is simply "server". h4. +script/rails+ -This file looks like this: +This file is as follows: APP_PATH = File.expand_path('../../config/application', __FILE__) @@ -130,7 +130,7 @@ require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' -The +APP_PATH+ constant here will be used later in +rails/commands+. The +config/boot+ file that +script/rails+ references is the +config/boot.rb+ file in our application which is responsible for loading Bundler and setting it up. +The +APP_PATH+ constant will be used later in +rails/commands+. The +config/boot+ file referenced here is the +config/boot.rb+ file in our application which is responsible for loading Bundler and setting it up. h4. +config/boot.rb+ -- cgit v1.2.3 From 5c61b7230eaa316ce64f4031234b425c35668988 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Tue, 22 Nov 2011 23:14:13 +0530 Subject: Revert "Added links to the 'Rails Initialization Guide', marked as a work in progress" This reverts commit 6b4939c3fd22924ee3d906f08fe739d848f80a3d. Reason: This guide is still incomplete and is not yet reviewed or ready to go to the index. --- railties/guides/source/index.html.erb | 4 ---- railties/guides/source/layout.html.erb | 1 - 2 files changed, 5 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index a8e12174ed..c9a8c4fa5c 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -134,10 +134,6 @@ Ruby on Rails Guides <%= guide('Asset Pipeline', 'asset_pipeline.html') do %>

This guide documents the asset pipeline.

<% end %> - -<%= guide('The Rails Initialization Process', 'initialization.html', :work_in_progress => true) do %> -

This guide explains the internals of the Rails initialization process as of Rails 3.1

-<% end %>

Extending Rails

diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index 83a17988ab..4c979888b7 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -72,7 +72,6 @@
Rails Command Line Tools and Rake Tasks
Caching with Rails
Asset Pipeline
-
Rails Initialization Process
Extending Rails
The Basics of Creating Rails Plugins
-- cgit v1.2.3 From 05e02deb686fc21f99c2d1dcf3abc987796e0e19 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Tue, 22 Nov 2011 15:16:23 -0500 Subject: Make explicit the default media when calling stylesheet_tag and change the default generators. --- .../guides/code/getting_started/app/views/layouts/application.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/code/getting_started/app/views/layouts/application.html.erb b/railties/guides/code/getting_started/app/views/layouts/application.html.erb index 1e1e4b9a99..7fd6b4f516 100644 --- a/railties/guides/code/getting_started/app/views/layouts/application.html.erb +++ b/railties/guides/code/getting_started/app/views/layouts/application.html.erb @@ -2,7 +2,7 @@ Blog - <%= stylesheet_link_tag "application" %> + <%= stylesheet_link_tag "application", :media => "all" %> <%= javascript_include_tag "application" %> <%= csrf_meta_tags %> -- cgit v1.2.3 From 6da52c617e2a075b9d9e7142786f316d8f2c7930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 23 Nov 2011 23:22:46 +0000 Subject: Remove listings from the serialization guide that won't make 3.2. --- railties/guides/source/serializers.textile | 37 ------------------------------ 1 file changed, 37 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/serializers.textile b/railties/guides/source/serializers.textile index 86a5e5ac8d..efc7cbf248 100644 --- a/railties/guides/source/serializers.textile +++ b/railties/guides/source/serializers.textile @@ -459,25 +459,6 @@ In other words, if a +PostSerializer+ is trying to serialize comments, it will f look for +PostSerializer::CommentSerializer+ before falling back to +CommentSerializer+ and finally +comment.as_json+. -h3. Optional Associations - -In some cases, you will want to allow a front-end to decide whether to include associated -content or not. You can achieve this easily by making an association *optional*. - - -class PostSerializer < ActiveModel::Serializer - attributes :title. :body - has_many :comments, :optional => true - - # ... -end - - -If an association is optional, it will not be included unless the request asks for it -with an +including+ parameter. The +including+ parameter is a comma-separated list of -optional associations to include. If the +including+ parameter includes an association -you did not specify in your serializer, it will receive a +401 Forbidden+ response. - h3. Overriding the Defaults h4. Authorization Scope @@ -500,24 +481,6 @@ which allows you to define a dynamic authorization scope based on the current re WARNING: If you use different objects as authorization scopes, make sure that they all implement whatever interface you use in your serializers to control what the outputted JSON looks like. -h4. Parameter to Specify Included Optional Associations - -In most cases, you should be able to use the default +including+ parameter to specify -which optional associations to include. If you are already using that parameter name or -want to reserve it for some reason, you can specify a different name by using the -+serialization_includes_param+ class method. - - -class PostsController < ApplicationController - serialization_includes_param :associations_to_include -end - - -You can also implement a +serialization_includes+ instance method, which should return an -Array of optional includes. - -WARNING: If you implement +serialization_includes+ and return an invalid association, your user will receive a +401 Forbidden+ exception. - h3. Using Serializers Outside of a Request The serialization API encapsulates the concern of generating a JSON representation of -- cgit v1.2.3 From 0e7443060b298d080292b18a5888aaf554cce344 Mon Sep 17 00:00:00 2001 From: Michael Pearson Date: Thu, 24 Nov 2011 10:33:04 +1100 Subject: Add step to getting_started to install JS Runtime. abstrakt on #rubyonrails found that the guide, when followed step by step, does fails at the 'rails server' command due to a lacking JS runtime. --- railties/guides/source/getting_started.textile | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index fde83ae730..55415dd41b 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -250,6 +250,18 @@ $ rails --version If it says something like "Rails 3.1.1" you are ready to continue. +h5. Installing a JavaScript Runtime + +By default, Rails requires a JavaScript interpreter to compile CoffeeScript to JavaScript. + +You can install one by running: + + +# gem install therubyracer + + +Or investigate the list of alternatives give by "ExecJS":https://github.com/sstephenson/execjs. + h4. Creating the Blog Application To begin, open a terminal, navigate to a folder where you have rights to create -- cgit v1.2.3 From ef38c3089e1269e2b315aff503e61c0b23c95f00 Mon Sep 17 00:00:00 2001 From: Michael Pearson Date: Thu, 24 Nov 2011 10:59:29 +1100 Subject: Move JS runtime instructions to where the error would be encountered, remove gem install. --- railties/guides/source/getting_started.textile | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 55415dd41b..5774eba5ae 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -250,18 +250,6 @@ $ rails --version If it says something like "Rails 3.1.1" you are ready to continue. -h5. Installing a JavaScript Runtime - -By default, Rails requires a JavaScript interpreter to compile CoffeeScript to JavaScript. - -You can install one by running: - - -# gem install therubyracer - - -Or investigate the list of alternatives give by "ExecJS":https://github.com/sstephenson/execjs. - h4. Creating the Blog Application To begin, open a terminal, navigate to a folder where you have rights to create @@ -462,6 +450,12 @@ start a web server on your development machine. You can do this by running: $ rails server +TIP: Some environments require that you install a JavaScript runtime to compile +CoffeeScript to JavaScript and will give you an +execjs+ error the first time +you run +rails server+. +therubyracer+ and +therubyrhino+ are commonly used +runtimes for Ruby and JRuby respectively. You can also investigate a list +of runtimes at "ExecJS":https://github.com/sstephenson/execjs. + This will fire up an instance of the WEBrick web server by default (Rails can also use several other web servers). To see your application in action, open a browser window and navigate to "http://localhost:3000":http://localhost:3000. -- cgit v1.2.3 From 510502ee3abfc8feacdf82868013f2f81676c8ff Mon Sep 17 00:00:00 2001 From: rpq Date: Wed, 23 Nov 2011 23:23:48 -0500 Subject: comma --- railties/guides/source/active_support_core_extensions.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index ff6c5f967f..da70f9206d 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -571,7 +571,7 @@ NOTE: Defined in +active_support/core_ext/module/attr_accessor_with_default.rb+. h5. Internal Attributes -When you are defining an attribute in a class that is meant to be subclassed name collisions are a risk. That's remarkably important for libraries. +When you are defining an attribute in a class that is meant to be subclassed, name collisions are a risk. That's remarkably important for libraries. Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby built-in +attr_*+ counterparts, except they name the underlying instance variable in a way that makes collisions less likely. -- cgit v1.2.3 From 0a4035b12a6c59253cb60f9e3456513c6a6a9d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 25 Nov 2011 19:29:39 +0000 Subject: Revert the serializers API as other alternatives are now also under discussion --- railties/guides/source/serializers.textile | 563 ----------------------------- 1 file changed, 563 deletions(-) delete mode 100644 railties/guides/source/serializers.textile (limited to 'railties/guides') diff --git a/railties/guides/source/serializers.textile b/railties/guides/source/serializers.textile deleted file mode 100644 index efc7cbf248..0000000000 --- a/railties/guides/source/serializers.textile +++ /dev/null @@ -1,563 +0,0 @@ -h2. Rails Serializers - -This guide describes how to use Active Model serializers to build non-trivial JSON services in Rails. By reading this guide, you will learn: - -* When to use the built-in Active Model serialization -* When to use a custom serializer for your models -* How to use serializers to encapsulate authorization concerns -* How to create serializer templates to describe the application-wide structure of your serialized JSON -* How to build resources not backed by a single database table for use with JSON services - -This guide covers an intermediate topic and assumes familiarity with Rails conventions. It is suitable for applications that expose a -JSON API that may return different results based on the authorization status of the user. - -endprologue. - -h3. Serialization - -By default, Active Record objects can serialize themselves into JSON by using the `to_json` method. This method takes a series of additional -parameter to control which properties and associations Rails should include in the serialized output. - -When building a web application that uses JavaScript to retrieve JSON data from the server, this mechanism has historically been the primary -way that Rails developers prepared their responses. This works great for simple cases, as the logic for serializing an Active Record object -is neatly encapsulated in Active Record itself. - -However, this solution quickly falls apart in the face of serialization requirements based on authorization. For instance, a web service -may choose to expose additional information about a resource only if the user is entitled to access it. In addition, a JavaScript front-end -may want information that is not neatly described in terms of serializing a single Active Record object, or in a different format than. - -In addition, neither the controller nor the model seems like the correct place for logic that describes how to serialize an model object -*for the current user*. - -Serializers solve these problems by encapsulating serialization in an object designed for this purpose. If the default +to_json+ semantics, -with at most a few configuration options serve your needs, by all means continue to use the built-in +to_json+. If you find yourself doing -hash-driven-development in your controllers, juggling authorization logic and other concerns, serializers are for you! - -h3. The Most Basic Serializer - -A basic serializer is a simple Ruby object named after the model class it is serializing. - - -class PostSerializer - def initialize(post, scope) - @post, @scope = post, scope - end - - def as_json - { post: { title: @post.name, body: @post.body } } - end -end - - -A serializer is initialized with two parameters: the model object it should serialize and an authorization scope. By default, the -authorization scope is the current user (+current_user+) but you can use a different object if you want. The serializer also -implements an +as_json+ method, which returns a Hash that will be sent to the JSON encoder. - -Rails will transparently use your serializer when you use +render :json+ in your controller. - - -class PostsController < ApplicationController - def show - @post = Post.find(params[:id]) - render json: @post - end -end - - -Because +respond_with+ uses +render :json+ under the hood for JSON requests, Rails will automatically use your serializer when -you use +respond_with+ as well. - -h4. +serializable_hash+ - -In general, you will want to implement +serializable_hash+ and +as_json+ to allow serializers to embed associated content -directly. The easiest way to implement these two methods is to have +as_json+ call +serializable_hash+ and insert the root. - - -class PostSerializer - def initialize(post, scope) - @post, @scope = post, scope - end - - def serializable_hash - { title: @post.name, body: @post.body } - end - - def as_json - { post: serializable_hash } - end -end - - -h4. Authorization - -Let's update our serializer to include the email address of the author of the post, but only if the current user has superuser -access. - - -class PostSerializer - def initialize(post, scope) - @post, @scope = post, scope - end - - def as_json - { post: serializable_hash } - end - - def serializable_hash - hash = post - hash.merge!(super_data) if super? - hash - end - -private - def post - { title: @post.name, body: @post.body } - end - - def super_data - { email: @post.email } - end - - def super? - @scope.superuser? - end -end - - -h4. Testing - -One benefit of encapsulating our objects this way is that it becomes extremely straight-forward to test the serialization -logic in isolation. - - -require "ostruct" - -class PostSerializerTest < ActiveSupport::TestCase - # For now, we use a very simple authorization structure. These tests will need - # refactoring if we change that. - plebe = OpenStruct.new(super?: false) - god = OpenStruct.new(super?: true) - - post = OpenStruct.new(title: "Welcome to my blog!", body: "Blah blah blah", email: "tenderlove@gmail.com") - - test "a regular user sees just the title and body" do - json = PostSerializer.new(post, plebe).to_json - hash = JSON.parse(json) - - assert_equal post.title, hash.delete("title") - assert_equal post.body, hash.delete("body") - assert_empty hash - end - - test "a superuser sees the title, body and email" do - json = PostSerializer.new(post, god).to_json - hash = JSON.parse(json) - - assert_equal post.title, hash.delete("title") - assert_equal post.body, hash.delete("body") - assert_equal post.email, hash.delete("email") - assert_empty hash - end -end - - -It's important to note that serializer objects define a clear interface specifically for serializing an existing object. -In this case, the serializer expects to receive a post object with +name+, +body+ and +email+ attributes and an authorization -scope with a +super?+ method. - -By defining a clear interface, it's must easier to ensure that your authorization logic is behaving correctly. In this case, -the serializer doesn't need to concern itself with how the authorization scope decides whether to set the +super?+ flag, just -whether it is set. In general, you should document these requirements in your serializer files and programatically via tests. -The documentation library +YARD+ provides excellent tools for describing this kind of requirement: - - -class PostSerializer - # @param [~body, ~title, ~email] post the post to serialize - # @param [~super] scope the authorization scope for this serializer - def initialize(post, scope) - @post, @scope = post, scope - end - - # ... -end - - -h3. Attribute Sugar - -To simplify this process for a number of common cases, Rails provides a default superclass named +ActiveModel::Serializer+ -that you can use to implement your serializers. - -For example, you will sometimes want to simply include a number of existing attributes from the source model into the outputted -JSON. In the above example, the +title+ and +body+ attributes were always included in the JSON. Let's see how to use -+ActiveModel::Serializer+ to simplify our post serializer. - - -class PostSerializer < ActiveModel::Serializer - attributes :title, :body - - def initialize(post, scope) - @post, @scope = post, scope - end - - def serializable_hash - hash = attributes - hash.merge!(super_data) if super? - hash - end - -private - def super_data - { email: @post.email } - end - - def super? - @scope.superuser? - end -end - - -First, we specified the list of included attributes at the top of the class. This will create an instance method called -+attributes+ that extracts those attributes from the post model. - -NOTE: Internally, +ActiveModel::Serializer+ uses +read_attribute_for_serialization+, which defaults to +read_attribute+, which defaults to +send+. So if you're rolling your own models for use with the serializer, you can use simple Ruby accessors for your attributes if you like. - -Next, we use the attributes methood in our +serializable_hash+ method, which allowed us to eliminate the +post+ method we hand-rolled -earlier. We could also eliminate the +as_json+ method, as +ActiveModel::Serializer+ provides a default +as_json+ method for -us that calls our +serializable_hash+ method and inserts a root. But we can go a step further! - - -class PostSerializer < ActiveModel::Serializer - attributes :title, :body - -private - def attributes - hash = super - hash.merge!(email: post.email) if super? - hash - end - - def super? - @scope.superuser? - end -end - - -The superclass provides a default +initialize+ method as well as a default +serializable_hash+ method, which uses -+attributes+. We can call +super+ to get the hash based on the attributes we declared, and then add in any additional -attributes we want to use. - -NOTE: +ActiveModel::Serializer+ will create an accessor matching the name of the current class for the resource you pass in. In this case, because we have defined a PostSerializer, we can access the resource with the +post+ accessor. - -h3. Associations - -In most JSON APIs, you will want to include associated objects with your serialized object. In this case, let's include -the comments with the current post. - - -class PostSerializer < ActiveModel::Serializer - attributes :title, :body - has_many :comments - -private - def attributes - hash = super - hash.merge!(email: post.email) if super? - hash - end - - def super? - @scope.superuser? - end -end - - -The default +serializable_hash+ method will include the comments as embedded objects inside the post. - - -{ - post: { - title: "Hello Blog!", - body: "This is my first post. Isn't it fabulous!", - comments: [ - { - title: "Awesome", - body: "Your first post is great" - } - ] - } -} - - -Rails uses the same logic to generate embedded serializations as it does when you use +render :json+. In this case, -because you didn't define a +CommentSerializer+, Rails used the default +as_json+ on your comment object. - -If you define a serializer, Rails will automatically instantiate it with the existing authorization scope. - - -class CommentSerializer - def initialize(comment, scope) - @comment, @scope = comment, scope - end - - def serializable_hash - { title: @comment.title } - end - - def as_json - { comment: serializable_hash } - end -end - - -If we define the above comment serializer, the outputted JSON will change to: - - -{ - post: { - title: "Hello Blog!", - body: "This is my first post. Isn't it fabulous!", - comments: [{ title: "Awesome" }] - } -} - - -Let's imagine that our comment system allows an administrator to kill a comment, and we only want to allow -users to see the comments they're entitled to see. By default, +has_many :comments+ will simply use the -+comments+ accessor on the post object. We can override the +comments+ accessor to limit the comments used -to just the comments we want to allow for the current user. - - -class PostSerializer < ActiveModel::Serializer - attributes :title. :body - has_many :comments - -private - def attributes - hash = super - hash.merge!(email: post.email) if super? - hash - end - - def comments - post.comments_for(scope) - end - - def super? - @scope.superuser? - end -end - - -+ActiveModel::Serializer+ will still embed the comments, but this time it will use just the comments -for the current user. - -NOTE: The logic for deciding which comments a user should see still belongs in the model layer. In general, you should encapsulate concerns that require making direct Active Record queries in scopes or public methods on your models. - -h3. Customizing Associations - -Not all front-ends expect embedded documents in the same form. In these cases, you can override the -default +serializable_hash+, and use conveniences provided by +ActiveModel::Serializer+ to avoid having to -build up the hash manually. - -For example, let's say our front-end expects the posts and comments in the following format: - - -{ - post: { - id: 1 - title: "Hello Blog!", - body: "This is my first post. Isn't it fabulous!", - comments: [1,2] - }, - comments: [ - { - id: 1 - title: "Awesome", - body: "Your first post is great" - }, - { - id: 2 - title: "Not so awesome", - body: "Why is it so short!" - } - ] -} - - -We could achieve this with a custom +as_json+ method. We will also need to define a serializer for comments. - - -class CommentSerializer < ActiveModel::Serializer - attributes :id, :title, :body - - # define any logic for dealing with authorization-based attributes here -end - -class PostSerializer < ActiveModel::Serializer - attributes :title, :body - has_many :comments - - def as_json - { post: serializable_hash }.merge!(associations) - end - - def serializable_hash - post_hash = attributes - post_hash.merge!(association_ids) - post_hash - end - -private - def attributes - hash = super - hash.merge!(email: post.email) if super? - hash - end - - def comments - post.comments_for(scope) - end - - def super? - @scope.superuser? - end -end - - -Here, we used two convenience methods: +associations+ and +association_ids+. The first, -+associations+, creates a hash of all of the define associations, using their defined -serializers. The second, +association_ids+, generates a hash whose key is the association -name and whose value is an Array of the association's keys. - -The +association_ids+ helper will use the overridden version of the association, so in -this case, +association_ids+ will only include the ids of the comments provided by the -+comments+ method. - -h3. Special Association Serializers - -So far, associations defined in serializers use either the +as_json+ method on the model -or the defined serializer for the association type. Sometimes, you may want to serialize -associated models differently when they are requested as part of another resource than -when they are requested on their own. - -For instance, we might want to provide the full comment when it is requested directly, -but only its title when requested as part of the post. To achieve this, you can define -a serializer for associated objects nested inside the main serializer. - - -class PostSerializer < ActiveModel::Serializer - class CommentSerializer < ActiveModel::Serializer - attributes :id, :title - end - - # same as before - # ... -end - - -In other words, if a +PostSerializer+ is trying to serialize comments, it will first -look for +PostSerializer::CommentSerializer+ before falling back to +CommentSerializer+ -and finally +comment.as_json+. - -h3. Overriding the Defaults - -h4. Authorization Scope - -By default, the authorization scope for serializers is +:current_user+. This means -that when you call +render json: @post+, the controller will automatically call -its +current_user+ method and pass that along to the serializer's initializer. - -If you want to change that behavior, simply use the +serialization_scope+ class -method. - - -class PostsController < ApplicationController - serialization_scope :current_app -end - - -You can also implement an instance method called (no surprise) +serialization_scope+, -which allows you to define a dynamic authorization scope based on the current request. - -WARNING: If you use different objects as authorization scopes, make sure that they all implement whatever interface you use in your serializers to control what the outputted JSON looks like. - -h3. Using Serializers Outside of a Request - -The serialization API encapsulates the concern of generating a JSON representation of -a particular model for a particular user. As a result, you should be able to easily use -serializers, whether you define them yourself or whether you use +ActiveModel::Serializer+ -outside a request. - -For instance, if you want to generate the JSON representation of a post for a user outside -of a request: - - -user = get_user # some logic to get the user in question -PostSerializer.new(post, user).to_json # reliably generate JSON output - - -If you want to generate JSON for an anonymous user, you should be able to use whatever -technique you use in your application to generate anonymous users outside of a request. -Typically, that means creating a new user and not saving it to the database: - - -user = User.new # create a new anonymous user -PostSerializer.new(post, user).to_json - - -In general, the better you encapsulate your authorization logic, the more easily you -will be able to use the serializer outside of the context of a request. For instance, -if you use an authorization library like Cancan, which uses a uniform +user.can?(action, model)+, -the authorization interface can very easily be replaced by a plain Ruby object for -testing or usage outside the context of a request. - -h3. Collections - -So far, we've talked about serializing individual model objects. By default, Rails -will serialize collections, including when using the +associations+ helper, by -looping over each element of the collection, calling +serializable_hash+ on the element, -and then grouping them by their type (using the plural version of their class name -as the root). - -For example, an Array of post objects would serialize as: - - -{ - posts: [ - { - title: "FIRST POST!", - body: "It's my first pooooost" - }, - { title: "Second post!", - body: "Zomg I made it to my second post" - } - ] -} - - -If you want to change the behavior of serialized Arrays, you need to create -a custom Array serializer. - - -class ArraySerializer < ActiveModel::ArraySerializer - def serializable_array - serializers.map do |serializer| - serializer.serializable_hash - end - end - - def as_json - hash = { root => serializable_array } - hash.merge!(associations) - hash - end -end - - -When generating embedded associations using the +associations+ helper inside a -regular serializer, it will create a new ArraySerializer with the -associated content and call its +serializable_array+ method. In this case, those -embedded associations will not recursively include associations. - -When generating an Array using +render json: posts+, the controller will invoke -the +as_json+ method, which will include its associations and its root. -- cgit v1.2.3 From 3f1a4c3415113f2d365eb1a5531757699afec605 Mon Sep 17 00:00:00 2001 From: gregolsen Date: Sun, 6 Nov 2011 21:42:03 +0200 Subject: beginning_of_week extended in both Time and Date so that to return week start based on start day that is monday by default --- railties/guides/source/active_support_core_extensions.textile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index ff6c5f967f..c6130f4f62 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -3039,12 +3039,14 @@ Active Support defines these methods as well for Ruby 1.8. h6. +beginning_of_week+, +end_of_week+ -The methods +beginning_of_week+ and +end_of_week+ return the dates for the beginning and end of week, assuming weeks start on Monday: +The methods +beginning_of_week+ and +end_of_week+ receive a symbol with a day name in English (in lowercase, default is :monday) and return the dates for the beginning and end of week, assuming weeks start on day, passed as parameter: -d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.beginning_of_week # => Mon, 03 May 2010 -d.end_of_week # => Sun, 09 May 2010 +d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 +d.beginning_of_week # => Mon, 03 May 2010 +d.beginning_of_week(:sunday) # => Sun, 02 May 2010 +d.end_of_week # => Sun, 09 May 2010 +d.end_of_week(:sunday) # => Sat, 08 May 2010 +beginning_of_week+ is aliased to +monday+ and +at_beginning_of_week+. +end_of_week+ is aliased to +sunday+ and +at_end_of_week+. -- cgit v1.2.3 From a5b362df567ed4a0167a83e9b8f00b9f614ac38b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 25 Nov 2011 12:01:58 -0800 Subject: some tweaks to PR#3547. [Closes #3547] --- railties/guides/source/active_support_core_extensions.textile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index c6130f4f62..09f931050d 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -3039,7 +3039,9 @@ Active Support defines these methods as well for Ruby 1.8. h6. +beginning_of_week+, +end_of_week+ -The methods +beginning_of_week+ and +end_of_week+ receive a symbol with a day name in English (in lowercase, default is :monday) and return the dates for the beginning and end of week, assuming weeks start on day, passed as parameter: +The methods +beginning_of_week+ and +end_of_week+ return the dates for the +beginning and end of the week, respectively. Weeks are assumed to start on +Monday, but that can be changed passing an argument, see examples: d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -- cgit v1.2.3 From 1be9830d4d99e2bf56f1cadf74b843f22d66da35 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 25 Nov 2011 14:29:34 -0800 Subject: add the query to AR::Relation#explain output Rationale: this is more readable if serveral queries are involved in one call. Also, it will be possible to let AR log EXPLAINs automatically in production mode, where queries are not even around. --- railties/guides/source/active_record_querying.textile | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index ad12dca7e8..0f1f6eba4c 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -1287,6 +1287,7 @@ User.where(:id => 1).joins(:posts).explain may yield +EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 ------------------------------------------------------------------------------------------ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ------------------------------------------------------------------------------------------ @@ -1302,6 +1303,7 @@ Active Record performs a pretty printing that emulates the one of the database shells. So, the same query running with the PostgreSQL adapter would yield instead +EXPLAIN for: SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."id" = 1 QUERY PLAN ------------------------------------------------------------------------------ Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0) @@ -1324,12 +1326,15 @@ User.where(:id => 1).includes(:posts).explain yields +EXPLAIN for: SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ------------------------------------------------------------------------------------ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ------------------------------------------------------------------------------------ | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | | ------------------------------------------------------------------------------------ 1 row in set (0.00 sec) + +EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1) ------------------------------------------------------------------------------------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ------------------------------------------------------------------------------------- -- cgit v1.2.3 From b30b932447d3ae059c0dac2c5bf0a3a79e0fa54e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 25 Nov 2011 14:58:43 -0800 Subject: finders guide: adds some pointers to help users interpret the output of EXPLAIN --- railties/guides/source/active_record_querying.textile | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 0f1f6eba4c..c4724f182e 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -1344,3 +1344,14 @@ EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1) under MySQL. + +h4. Interpreting EXPLAIN + +Interpretation of the output of EXPLAIN is beyond the scope of this guide. The +following pointers may be helpful: + +* SQLite3: "EXPLAIN QUERY PLAN":http://www.sqlite.org/eqp.html + +* MySQL: "EXPLAIN Output Format":http://dev.mysql.com/doc/refman/5.6/en/explain-output.html + +* PostgreSQL: "Using EXPLAIN":http://www.postgresql.org/docs/current/static/using-explain.html -- cgit v1.2.3 From 5c2a2ee76e2af591a997b71eec0e35143c07f9e1 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 26 Nov 2011 19:06:53 +0530 Subject: rephrased ef38c3089e1269e2b315aff503e61c0b23c95f00 and mentioned about OS X and windows usually having a JS runtime --- railties/guides/source/getting_started.textile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'railties/guides') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 5774eba5ae..ca6a404212 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -450,11 +450,7 @@ start a web server on your development machine. You can do this by running: $ rails server -TIP: Some environments require that you install a JavaScript runtime to compile -CoffeeScript to JavaScript and will give you an +execjs+ error the first time -you run +rails server+. +therubyracer+ and +therubyrhino+ are commonly used -runtimes for Ruby and JRuby respectively. You can also investigate a list -of runtimes at "ExecJS":https://github.com/sstephenson/execjs. +TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the absence of a runtime will give you an +execjs+ error. Usually Mac OS X and Windows come with a JavaScript runtime installed. +therubyracer+ and +therubyrhino+ are the commonly used runtimes for Ruby and JRuby respectively. You can also investigate a list of runtimes at "ExecJS":https://github.com/sstephenson/execjs. This will fire up an instance of the WEBrick web server by default (Rails can also use several other web servers). To see your application in action, open a -- cgit v1.2.3 From fc20d6b6815032935f02b53b4b928cd514ed66ac Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sat, 26 Nov 2011 22:38:58 +0530 Subject: Let's say this 3.1.3 instead of 3.1.1 in docs --- railties/guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index ca6a404212..fe43c9db36 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -248,7 +248,7 @@ the following: $ rails --version -If it says something like "Rails 3.1.1" you are ready to continue. +If it says something like "Rails 3.1.3" you are ready to continue. h4. Creating the Blog Application -- cgit v1.2.3 From 0ce64ba9aa93c01ee69c45493ad8090e76f95ff4 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sun, 27 Nov 2011 12:34:14 +0530 Subject: Documentation about config.log_level config options --- railties/guides/source/configuring.textile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'railties/guides') diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 809948b41e..beb623757b 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -88,6 +88,8 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is * +config.log_level+ defines the verbosity of the Rails logger. This option defaults to +:debug+ for all modes except production, where it defaults to +:info+. +* +config.log_tags+ accepts a list of methods that respond to +request+ object. This makes it easy to tag log lines with debug information like subdomain and request id -- both very helpful in debugging multi-user production applications. + * +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby +Logger+ class. Defaults to an instance of +ActiveSupport::BufferedLogger+, with auto flushing off in production mode. * +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below. -- cgit v1.2.3 From 28e3935360c9392685c4954791cc320ed02e15c0 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sun, 27 Nov 2011 12:53:08 +0530 Subject: [Docs] Adding RequestId middleware in configuring middleware --- railties/guides/source/configuring.textile | 1 + 1 file changed, 1 insertion(+) (limited to 'railties/guides') diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index beb623757b..d91011c370 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -190,6 +190,7 @@ Every Rails application comes with a standard set of middleware which it uses in * +Rack::Runtime+ sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request. * +Rails::Rack::Logger+ notifies the logs that the request has began. After request is complete, flushes all the logs. * +ActionDispatch::ShowExceptions+ rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to +true+. If +config.action_dispatch.show_exceptions+ is set to +false+, exceptions will be raised regardless. +* +ActionDispatch::RequestId+ makes a unique X-Request-Id header available to the response and enables the +ActionDispatch::Request#uuid+ method. * +ActionDispatch::RemoteIp+ checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings. * +Rack::Sendfile+ intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+. * +ActionDispatch::Callbacks+ runs the prepare callbacks before serving the request. -- cgit v1.2.3 From 9cf285599c1e99736f5dd9d01f986c19dcf3d4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadas=20Tamo=C5=A1auskas?= Date: Sun, 27 Nov 2011 12:44:14 +0000 Subject: Update Object#in? description for https://github.com/rails/rails/pull/3767 --- railties/guides/source/active_support_core_extensions.textile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index d601e9ea29..c1046a3b63 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -440,14 +440,16 @@ NOTE: Defined in +active_support/core_ext/kernel/reporting.rb+. h4. +in?+ -The predicate +in?+ tests if an object is included in another object. An +ArgumentError+ exception will be raised if the argument passed does not respond to +include?+. +The predicate +in?+ tests if an object is included in another object or a list of objects. An +ArgumentError+ exception will be raised if a single argument is passed and it does not respond to +include?+. Examples of +in?+: +1.in?(1,2) # => true 1.in?([1,2]) # => true "lo".in?("hello") # => true 25.in?(30..50) # => false +1.in?(1) # => ArgumentError NOTE: Defined in +active_support/core_ext/object/inclusion.rb+. -- cgit v1.2.3 From 2f428a6245a18017c7942f8fef3da4a85bec8cc5 Mon Sep 17 00:00:00 2001 From: Tim Reischmann Date: Mon, 28 Nov 2011 09:27:42 +0100 Subject: fixed typo in getting started form_for for comments --- railties/guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index fe43c9db36..3ff6603a4c 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1297,7 +1297,7 @@ So first, we'll wire up the Post show template

Add a comment:

-<%= form_for([@post, @post.comments.build]) do |f| %> +<%= form_for([@post, @post.comment.build]) do |f| %>
<%= f.label :commenter %>
<%= f.text_field :commenter %> -- cgit v1.2.3 From e7dff9c1f1e3e8a73c1b5bc5fd4263126813489c Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Mon, 28 Nov 2011 14:10:23 +0530 Subject: Revert "fixed typo in getting started form_for for comments" This reverts commit 2f428a6245a18017c7942f8fef3da4a85bec8cc5. See comments here 2f428a6245a18017c7942f8fef3da4a85bec8cc5 --- railties/guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 3ff6603a4c..fe43c9db36 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1297,7 +1297,7 @@ So first, we'll wire up the Post show template

Add a comment:

-<%= form_for([@post, @post.comment.build]) do |f| %> +<%= form_for([@post, @post.comments.build]) do |f| %>
<%= f.label :commenter %>
<%= f.text_field :commenter %> -- cgit v1.2.3 From 6d05c793cafe79860bcbb469d6c46c83c531ab34 Mon Sep 17 00:00:00 2001 From: Rodrigo Rosenfeld Rosas Date: Mon, 28 Nov 2011 13:15:07 -0200 Subject: Update information about foreign key plugins support in the guides There is not "a number" of up-to-date maintained plugins for dealing with foreign keys. The foreign_key_migrations does not have any update since 2009 and is also about to be removed: Extracted from http://www.harukizaemon.com/2009/09/plugins-grab-em-while-theyre-stale.html, referenced in the plugin reference of the old guide version: "And so it is that I will very shortly (within the next month) delete most of the plugins from my GitHub account (harukizaemon)" --- railties/guides/source/migrations.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'railties/guides') diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 5b52a93853..c63f2aa119 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -670,4 +670,4 @@ The Active Record way claims that intelligence belongs in your models, not in th Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level, these cannot guarantee referential integrity and so some people augment them with foreign key constraints. -Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. There are also a number of plugins such as "foreign_key_migrations":https://github.com/harukizaemon/redhillonrails/tree/master/foreign_key_migrations/ which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+). +Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. You could also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+). -- cgit v1.2.3