aboutsummaryrefslogtreecommitdiffstats
path: root/guides/source/engines.textile
diff options
context:
space:
mode:
Diffstat (limited to 'guides/source/engines.textile')
-rw-r--r--guides/source/engines.textile164
1 files changed, 153 insertions, 11 deletions
diff --git a/guides/source/engines.textile b/guides/source/engines.textile
index 86e7254201..fe8fcfbb3f 100644
--- a/guides/source/engines.textile
+++ b/guides/source/engines.textile
@@ -217,7 +217,7 @@ This helps prevent conflicts with any other engine or application that may have
Finally, two files that are the assets for this resource are generated, +app/assets/javascripts/blorgh/posts.js+ and +app/assets/javascripts/blorgh/posts.css+. You'll see how to use these a little later.
-By default, the scaffold styling is not applied to the engine as the engine's layout file, +app/views/blorgh/application.html.erb+ doesn't load it. To make this apply, insert this line into the +<head>+ tag of this layout:
+By default, the scaffold styling is not applied to the engine as the engine's layout file, +app/views/blorgh/application.html.erb+ doesn't load it. To make this apply, insert this line into the +&lt;head&gt;+ tag of this layout:
<erb>
<%= stylesheet_link_tag "scaffold" %>
@@ -347,7 +347,7 @@ The form will be making a +POST+ request to +/posts/:post_id/comments+, which wi
<ruby>
def create
@post = Post.find(params[:post_id])
- @comment = @post.comments.build(params[:comment])
+ @comment = @post.comments.create(params[:comment])
flash[:notice] = "Comment has been created!"
redirect_to post_path
end
@@ -369,7 +369,7 @@ This partial will be responsible for rendering just the comment text, for now. C
<%= comment_counter + 1 %>. <%= comment.text %>
</erb>
-The +comment_counter+ local variable is given to us by the +<%= render @post.comments %>+ call, as it will define this automatically and increment the counter as it iterates through each comment. It's used in this example to display a small number next to each comment when it's created.
+The +comment_counter+ local variable is given to us by the +&lt;%= render @post.comments %&gt;+ call, as it will define this automatically and increment the counter as it iterates through each comment. It's used in this example to display a small number next to each comment when it's created.
That completes the comment function of the blogging engine. Now it's time to use it within an application.
@@ -536,7 +536,7 @@ Finally, the author's name should be displayed on the post's page. Add this code
</p>
</erb>
-By outputting +@post.author+ using the +<%=+ tag the +to_s+ method will be called on the object. By default, this will look quite ugly:
+By outputting +@post.author+ using the +&lt;%=+ tag the +to_s+ method will be called on the object. By default, this will look quite ugly:
<plain>
#<User:0x00000100ccb3b0>
@@ -563,7 +563,7 @@ end
By default, the engine's controllers inherit from <tt>Blorgh::ApplicationController</tt>. So, after making this change they will have access to the main applications +ApplicationController+ as though they were part of the main application.
-This change does require that the engine is run from a Rails application that has an +ApplicationController+.
+This change does require that the engine is run from a Rails application that has an +ApplicationController+.
h4. Configuring an engine
@@ -655,7 +655,125 @@ This tells the application that you still want to perform a +GET+ request to the
h3. Improving engine functionality
-This section looks at overriding or adding functionality to the views, controllers and models provided by an engine.
+This section explains how to add and/or override engine MVC functionality in the main Rails application.
+
+h4. Overriding Models and Controllers
+
+Engine model and controller classes can be extended by open classing them in the main Rails application (since model and controller classes are just Ruby classes that inherit Rails specific functionality). Open classing an Engine class redefines it for use in the main applicaiton. This is usually implemented by using the decorator pattern.
+
+For simple class modifications use Class#class_eval, and for complex class modifications, consider using ActiveSupport::Concern.
+
+h5. Implementing Decorator Pattern Using Class#class_eval
+
+**Adding** Post#time_since_created,
+
+<ruby>
+# MyApp/app/decorators/models/blorgh/post_decorator.rb
+
+Blorgh::Post.class_eval do
+ def time_since_created
+ Time.current - created_at
+ end
+end
+</ruby>
+
+<ruby>
+# Blorgh/app/models/post.rb
+
+class Post < ActiveRecord::Base
+ :has_many :comments
+end
+</ruby>
+
+
+**Overriding** Post#summary
+
+<ruby>
+# MyApp/app/decorators/models/blorgh/post_decorator.rb
+
+Blorgh::Post.class_eval do
+ def summary
+ "#{title} - #{truncate(text)}"
+ end
+end
+</ruby>
+
+<ruby>
+# Blorgh/app/models/post.rb
+
+class Post < ActiveRecord::Base
+ :has_many :comments
+ def summary
+ "#{title}"
+ end
+end
+</ruby>
+
+
+h5. Implementing Decorator Pattern Using ActiveSupport::Concern
+
+Using Class#class_eval is great for simple adjustments, but for more complex class modifications, you might want to consider using ActiveSupport::Concern. ["**ActiveSupport::Concern**":http://edgeapi.rubyonrails.org/classes/ActiveSupport/Concern.html] helps manage load order of interlinked dependencies at run time allowing you to significantly modularize your code.
+
+**Adding** Post#time_since_created<br/>
+**Overriding** Post#summary
+
+<ruby>
+# MyApp/app/models/blorgh/post.rb
+
+class Blorgh::Post < ActiveRecord::Base
+ include Blorgh::Concerns::Models::Post
+
+ def time_since_created
+ Time.current - created_at
+ end
+
+ def summary
+ "#{title} - #{truncate(text)}"
+ end
+end
+</ruby>
+
+<ruby>
+# Blorgh/app/models/post.rb
+
+class Post < ActiveRecord::Base
+ include Blorgh::Concerns::Models::Post
+end
+</ruby>
+
+<ruby>
+# Blorgh/lib/concerns/models/post
+
+module Blorgh::Concerns::Models::Post
+ extend ActiveSupport::Concern
+
+ # 'included do' causes the included code to be evaluated in the
+ # conext where it is included (post.rb), rather than be
+ # executed in the module's context (blorgh/concerns/models/post).
+ included do
+ attr_accessor :author_name
+ belongs_to :author, :class_name => "User"
+
+ before_save :set_author
+
+ private
+
+ def set_author
+ self.author = User.find_or_create_by_name(author_name)
+ end
+ end
+
+ def summary
+ "#{title}"
+ end
+
+ module ClassMethods
+ def some_class_method
+ 'some class method string'
+ end
+ end
+end
+</ruby>
h4. Overriding views
@@ -734,12 +852,14 @@ You can also specify these assets as dependencies of other assets using the Asse
*/
</plain>
+INFO. Remember that in order to use languages like Sass or CoffeeScript, you should add the relevant library to your engine's +.gemspec+.
+
h4. Separate Assets & Precompiling
There are some situations where your engine's assets not required by the host application. For example, say that you've created
an admin functionality that only exists for your engine. In this case, the host application doesn't need to require +admin.css+
or +admin.js+. Only the gem's admin layout needs these assets. It doesn't make sense for the host app to include +"blorg/admin.css"+ in it's stylesheets. In this situation, you should explicitly define these assets for precompilation.
-This tells sprockets to add you engine assets when +rake assets:precompile+ is ran.
+This tells sprockets to add you engine assets when +rake assets:precompile+ is ran.
You can define assets for precompilation in +engine.rb+
@@ -753,18 +873,40 @@ For more information, read the "Asset Pipeline guide":http://guides.rubyonrails.
h4. Other gem dependencies
-Gem dependencies inside an engine should be specified inside the +.gemspec+ file that's at the root of the engine. The reason for this is because the engine may be installed as a gem. If dependencies were to be specified inside the +Gemfile+, these would not be recognised by a traditional gem install and so they would not be installed, causing the engine to malfunction.
+Gem dependencies inside an engine should be specified inside the +.gemspec+ file
+that's at the root of the engine. The reason for this is because the engine may
+be installed as a gem. If dependencies were to be specified inside the +Gemfile+,
+these would not be recognised by a traditional gem install and so they would not
+be installed, causing the engine to malfunction.
-To specify a dependency that should be installed with the engine during a traditional +gem install+, specify it inside the +Gem::Specification+ block inside the +.gemspec+ file in the engine:
+To specify a dependency that should be installed with the engine during a
+traditional +gem install+, specify it inside the +Gem::Specification+ block
+inside the +.gemspec+ file in the engine:
<ruby>
s.add_dependency "moo"
</ruby>
-To specify a dependency that should only be installed as a development dependency of the application, specify it like this:
+To specify a dependency that should only be installed as a development
+dependency of the application, specify it like this:
<ruby>
s.add_development_dependency "moo"
</ruby>
-Both kinds of dependencies will be installed when +bundle install+ is run inside the application. The development dependencies for the gem will only be used when the tests for the engine are running.
+Both kinds of dependencies will be installed when +bundle install+ is run inside
+the application. The development dependencies for the gem will only be used when
+the tests for the engine are running.
+
+Note that if you want to immediately require dependencies when the engine is
+required, you should require them before engine's initialization. For example:
+
+<ruby>
+require 'other_engine/engine'
+require 'yet_another_engine/engine'
+
+module MyEngine
+ class Engine < ::Rails::Engine
+ end
+end
+</ruby> \ No newline at end of file