diff options
-rw-r--r-- | activemodel/lib/active_model/serializers/xml.rb | 2 | ||||
-rw-r--r-- | activerecord/CHANGELOG.md | 13 | ||||
-rw-r--r-- | activerecord/lib/active_record/locking/optimistic.rb | 1 | ||||
-rw-r--r-- | activerecord/test/cases/locking_test.rb | 1 | ||||
-rw-r--r-- | guides/source/action_controller_overview.md | 86 | ||||
-rw-r--r-- | guides/source/asset_pipeline.md | 4 | ||||
-rw-r--r-- | guides/source/initialization.md | 2 | ||||
-rw-r--r-- | railties/lib/rails/application.rb | 1 | ||||
-rw-r--r-- | tasks/release.rb | 2 |
9 files changed, 106 insertions, 6 deletions
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb index 2803f69b6f..2864c2ba11 100644 --- a/activemodel/lib/active_model/serializers/xml.rb +++ b/activemodel/lib/active_model/serializers/xml.rb @@ -205,7 +205,7 @@ module ActiveModel Serializer.new(self, options).serialize(&block) end - # Sets the model +attributes+ from a JSON string. Returns +self+. + # Sets the model +attributes+ from an XML string. Returns +self+. # # class Person # include ActiveModel::Serializers::Xml diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 1eb2f2d130..404443f4ad 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,16 @@ +* Reset @column_defaults when assigning `locking_column`. + We had a potential problem. For example: + + class Post < ActiveRecord::Base + self.column_defaults # if we call this unintentionally before setting locking_column ... + self.locking_column = 'my_locking_column' + end + + Post.column_defaults["my_locking_column"] + => nil # expected value is 0 ! + + *kennyj* + * Remove extra select and update queries on save/touch/destroy ActiveRecord model with belongs to reflection with option `touch: true`. diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 209de78898..2a7996c4e7 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -138,6 +138,7 @@ module ActiveRecord # Set the column to use for optimistic locking. Defaults to +lock_version+. def locking_column=(value) + @column_defaults = nil @locking_column = value.to_s end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 827fcf3d50..db7d3b80ab 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -17,6 +17,7 @@ class LockWithoutDefault < ActiveRecord::Base; end class LockWithCustomColumnWithoutDefault < ActiveRecord::Base self.table_name = :lock_without_defaults_cust + self.column_defaults # to test @column_defaults caching. self.locking_column = :custom_lock_version end diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index f2abd833aa..ecaee02cce 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -907,6 +907,92 @@ Now the user can request to get a PDF version of a client just by adding ".pdf" GET /clients/1.pdf ``` +### Live Streaming of Arbitrary Data + +Rails allows you to stream more than just files. In fact, you can stream anything +you would like in a response object. The `ActionController::Live` module allows +you to create a persistent connection with a browser. Using this module, you will +be able to send arbitrary data to the browser at specific points in time. + +#### Incorporating Live Streaming + +Including `ActionController::Live` inside of your controller class will provide +all actions inside of the controller the ability to stream data. You can mix in +the module like so: + +```ruby +class MyController < ActionController::Base + include ActionController::Live + + def stream + response.headers['Content-Type'] = 'text/event-stream' + 100.times { + response.stream.write "hello world\n" + sleep 1 + } + ensure + response.stream.close + end +end +``` + +The above code will keep a persistent connection with the browser and send 100 +messages of `"hello world\n"`, each one second apart. + +There are a couple of things to notice in the above example. We need to make +sure to close the response stream. Forgetting to close the stream will leave +the socket open forever. We also have to set the content type to `text/event-stream` +before we write to the response stream. This is because headers cannot be written +after the response has been committed (when `response.committed` returns a truthy +value), which occurs when you `write` or `commit` the response stream. + +#### Example Usage + +Let's suppose that you were making a Karaoke machine and a user wants to get the +lyrics for a particular song. Each `Song` has a particular number of lines and +each line takes time `num_beats` to finish singing. + +If we wanted to return the lyrics in Karaoke fashion (only sending the line when +the singer has finished the previous line), then we could use `ActionController::Live` +as follows: + +```ruby +class LyricsController < ActionController::Base + include ActionController::Live + + def show + response.headers['Content-Type'] = 'text/event-stream' + song = Song.find(params[:id]) + + song.each do |line| + response.stream.write line.lyrics + sleep line.num_beats + end + ensure + response.stream.close + end +end +``` + +The above code sends the next line only after the singer has completed the previous +line. + +#### Streaming Considerations + +Streaming arbitrary data is an extremely powerful tool. As shown in the previous +examples, you can choose when and what to send across a response stream. However, +you should also note the following things: + +* Each response stream creates a new thread and copies over the thread local + variables from the original thread. Having too many thread local variables can + negatively impact performance. Similarly, a large number of threads can also + hinder performance. +* Failing to close the response stream will leave the corresponding socket open + forever. Make sure to call `close` whenever you are using a response stream. +* WEBrick servers buffer all responses, and so including `ActionController::Live` + will not work. You must use a web server which does not automatically buffer + responses. + Log Filtering ------------- diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index a6e3d3b0ac..6c4d7fe255 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -606,7 +606,7 @@ Customizing the Pipeline ### CSS Compression -There is currently one option for compressing CSS, YUI. The [YUI CSS compressor](http://developer.yahoo.com/yui/compressor/css.html) provides minification. +There is currently one option for compressing CSS, YUI. The [YUI CSS compressor](http://yui.github.io/yuicompressor/css.html) provides minification. The following line enables YUI compression, and requires the `yui-compressor` gem. @@ -620,7 +620,7 @@ The `config.assets.compress` must be set to `true` to enable CSS compression. Possible options for JavaScript compression are `:closure`, `:uglifier` and `:yui`. These require the use of the `closure-compiler`, `uglifier` or `yui-compressor` gems, respectively. -The default Gemfile includes [uglifier](https://github.com/lautis/uglifier). This gem wraps [UglifierJS](https://github.com/mishoo/UglifyJS) (written for NodeJS) in Ruby. It compresses your code by removing white space. It also includes other optimizations such as changing your `if` and `else` statements to ternary operators where possible. +The default Gemfile includes [uglifier](https://github.com/lautis/uglifier). This gem wraps [UglifyJS](https://github.com/mishoo/UglifyJS) (written for NodeJS) in Ruby. It compresses your code by removing white space and comments, shortening local variable names, and performing other micro-optimizations such as changing `if` and `else` statements to ternary operators where possible. The following line invokes `uglifier` for JavaScript compression. diff --git a/guides/source/initialization.md b/guides/source/initialization.md index 11c736585f..26259408b4 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -350,7 +350,7 @@ end The interesting part for a Rails app is the last line, `server.run`. Here we encounter the `wrapped_app` method again, which this time we're going to explore more (even though it was executed before, and -thus memorized by now). +thus memoized by now). ```ruby @wrapped_app ||= build_app app diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index f761bef664..4faaf5ef1e 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -289,7 +289,6 @@ module Rails railties.each { |r| r.run_tasks_blocks(app) } super require "rails/tasks" - config = self.config task :environment do ActiveSupport.on_load(:before_initialize) { config.eager_load = false } diff --git a/tasks/release.rb b/tasks/release.rb index 0c22f812fc..66da67bfd0 100644 --- a/tasks/release.rb +++ b/tasks/release.rb @@ -1,4 +1,4 @@ -FRAMEWORKS = %w( activesupport activemodel activerecord actionpack actionmailer railties ) +FRAMEWORKS = %w( activesupport activemodel activerecord actionpack actionview actionmailer railties ) root = File.expand_path('../../', __FILE__) version = File.read("#{root}/RAILS_VERSION").strip |