Extending a ActiveRecord class from a rails Engine - ruby-on-rails-3

I have a rails app which uses a ActiveRecord model defined in a rails engine. I want to add some methods to that class (in this case FormInstance), so I simply use the syntax:
class FormInstance
def mynewmethod
#..my code here..
end
end
But this doesn't seem to work. It does indeed create FormInstance class with the new method, but it's not extending the Engine class, all the original methods of the FormInstance class are gone. What's the correct way to do this?
Env: rail 3.2.13, ruby 2.0.0

You can do it with the decorator pattern. There are multiple ways of implementing it. Have a look at the activesupport-decorators gem. It hooks into Rails ActiveSupport and adds a convention to doing decorators that is safe from circular dependencies. We have been using it in production on multiple apps for a while.
https://github.com/EPI-USE-Labs/activesupport-decorators

Related

How I can organize namespace of classes in app/modules with rails?

[This is a follow-up question to "How I can modularize Rails model?"]
Is there anyway to organize classes in app/models directory of Rails?
Do I have to use single top-level namespace for all of the classes?
Initial motivation is, I want place business logic classes which do not inherited from ActiveRecord::Base into app/models directory. Searching this site reveals many answers which recommend to place business logics classes in the app/models directory. I posted a different question, and got recommendation that it is possible to place such classes into lib directory.
Now I'm curious. I'd like to place these classes into different namespace and directory in apps/models directory which recommended by others. Is it possible?
Actually, I experiment that, but it seems to me that is what rails is not expected. If I create such a class (like SomeModName::ClassInMod in some_mod_name/class_in_mod.rb ) it does not get loaded. Also, I defined constants inside the module. Since they're not loaded, I can't use them. Actually, with rspec it work without problem, but with rails server, the class does not loaded. I'm sure it is related to autoloading issue.
In addition to the classes mentioned above, classes inherited from ActiveRecord::Base can be placed into some namespaces inside a module. I'm curious whether this work well or not too.
So the question in other words: can I make rails happy by configuring these files to be loaded, or is not the way rails designed?
Yes, you can define an ActiveRecord class in a module. The easy way is to use the generator:
./script/rails generate model logic/phase_logic
./script/rails generate model logic/evaluation_logic
Observe, that Rails will create additionally a file with the definition of the module. In this case:
# app/models/logic.rb
module Logic
...
end
# app/models/logic/phase_logics.rb
class Logic::PhaseLogic < ActiveRecord::Base
...
end
# app/models/logic/evaluation_logics.rb
class Logic::EvaluationLogic < ActiveRecord::Base
...
end
Your problems with constants defined in the module were caused by the fact, that you defined the constants in the definition module "wrapped" around only one model, from the two you have created. A very important part in understanding ruby (and Rails) - especially for people who have strong background in compiled languages - is to remember that there is no compilation phase, so the definition of some class is read and executed only when that specific class is used. Sometimes a week after the application server has been started and served thousands of requests.
Thus, as I said in the previous question's answer, the problem with autoloading was that sometimes the definition of the constants was read after the definition which was trying to use them. The order was random - if the first used object happened to be EvaluationLogic, then the error emerged. It the first object happened to be PhaseLogic, everything was fine.
Now, when you have a file for the module itself, and define constants in that file (app/models/logic.rb), autoloading will be able to find and execute the definitions before any class starts to use them. I hope everything will be OK.

What does the :: indicate in Rails 3?

I am implementing an API in Rails 3, and noticed an example controller defined like class Api::ToursController < ApplicationController. Does anyone know what the to colons indicate? Is it inheritance? Or is it indicating extending the ToursController? I have tried searching for an answer, but have not come up with anything.
Here is what I am referencing: https://github.com/nesquena/rabl/wiki/Set-up-rabl-for-Ruby-on-Rails
:: is the scope resolution operator (i.e. namespace operator) in many languages, including C++ and Ruby, so it's not specific to Rails.
In Ruby, modules define namespaces, so you can see code like this:
Net::HTTP.get 'stackoverflow.com'
Which calls the get class method on the HTTP class in the Net module.
In Rails, namespaces allow you to better organize your code (e.g. to separate your API controllers from the rest), and are implemented as modules.
Api::ToursController indicates that there is an outer Module called Api , in which the ToursController class is located. :: is the namespace operator.
Sometimes you see a module name preceded with :: , e.g. ::Something , this indicates to Ruby to look in the outer-most namespace (Main) for the Class or Module called Something. This typically happens when you're somewhere in the source code of a gem and it references an outer Class or Module.
You can do include Api to include everything in the Module Api at the current level, this way you don't need the namespace operator, and can use ToursController without prefixing it with 'Api::'
It's namespace! Module::Class.method

Make all ActionViewer helper methods available in a module

I am using ruby on rails 3. I have a model called Content. Within the controller, I extract some variables and pass them to the Viewer. In the Viewer, I would like to use of my self made functions so that I don't have too much logic and code in the Viewer. I defined these functions in the ContentsHelper module.
My functions defined in the ContentsHelper module are making use of ActionViewer helper functions, however these are not available in the ContentsHelper module. I am getting for example NoMethodError: undefined method content_tag' for #<Content:0x1025b9458> error.
How is it possible to make all the ActionViewer helper functions available?
Newbie.
following suggestion of Tim:
module ContentsHelper
include ActionView::Helpers
def bla
content_tag(:h2, self.title)
end
I can run the bla method as Content.bla in the console. This is perfect!
But when I replacec content_tag with image_tag, then I run into trouble and get this error:
NoMethodError: undefined method `config'
from /Users/sonat/.rvm/gems/ruby-1.8.7-p334/gems/activemodel-3.0.0/lib/active_model/attribute_methods.rb:364:in `method_missing'
from /Users/sonat/.rvm/gems/ruby-1.8.7-p334/gems/activerecord-3.0.0/lib/active_record/attribute_methods.rb:46:in `method_missing'
from /Users/sonat/.rvm/gems/ruby-1.8.7-p334/gems/activerecord-3.0.0/lib/active_record/attribute_methods.rb:44:in `send'
I can see that module that is responsible of the image_tag method is missing "something". I would appreciate if you guys tell me the general approach in finding what is missing and how I could solve the problem.
Looks like you're trying to do something odd like to use the helper method inside your model instead of inside your view. Helper methods are for views, not for models.
Added
Tim asked if I could provide some links to other resources, but really this is such basic stuff that I'm not aware of anything dealing with this. Mostly tutorials deal with unusual things like using helpers outside views.
So instead, here's some code:
app/helpers/contents_helper.rb
module ContentsHelper
def foo
content_tag :p, "Foo"
end
end
app/views/contents/index.html.erb
<h1>Listing Contents</h1>
<%= foo %>
The HTML output when going to /contents URL
<h1>Listing Contents</h1>
<p>Foo</p>
And that's as hard as it is.
content_tag:
Does this work?
module ContentsHelper
include ActionView::Helpers
end
image_tag:
Looks like you'll have to make your models know where the images are located by implementing a #path_to_image(image) method.
I've set up a Gist for us to mock out the features you need here:
https://gist.github.com/1015333
You should be able to download and run forNoNameNo.rb (which should run quietly without errors.)
That file has some examples of what's needed to make image_tag work.
further discussion:
Helpers are probably the weirdest part of Rails. They're declared at the controller level, but are only included at the view level, and rely on weird parts of the controller stack for their info; and yet, the info they are mainly concerned with presenting is the model info. So they're spread across all these weird concerns.
To deal with code-organizations issues arising from all of this, people have tended toward the Presenter pattern. (Also see rbates' version)
That said, if you'd prefer to stray off the beaten path in rails, it's normally really useful to read the source code.
If you're using textmate:
mate `gem which actionpack`../action_view
in Terminal.app should get your there. If you're using another editor/operating system you might have to navigate to whereever gem which actionpack tells you to go.

rails3 gem: acts_as_something

I'm trying to extract some common code into a gem.
I'm thinking that acts_as_somethingis a good strategy for simple re-use.
Is there a good tutorial that discusses this for rails3 gems? I've found several that discuss rails2 (such as http://guides.rubyonrails.org/plugins.html) but that is specific to rails2
here are some of the tutorials/blogs I've already read:
http://guides.rubyonrails.org/plugins.html
http://www.thoughtsincomputation.com/categories/coding-gems-for-rails-3-tutorials (this is an excellent start but doesn't cover the act_as_* issue or controllers)
thanks
UPDATE: I've added a blog post based on this answer, but with much more detail: http://thoughtsincomputation.com/posts/coding-an-acts_as-gem-for-rails-3
--
I'm not aware of another tutorial source off the top of my head, but here are some general tips.
Rails 3 makes use of a really useful feature called Railtie - see http://api.rubyonrails.org/classes/Rails/Railtie.html .
So, if I were implementing an acts_as_* gem, I'd start there. My railtie might look something like:
# lib/acts_as_awesome/railtie.rb
require 'rails'
require 'acts_as_awesome'
module ActsAsAwesome
class Railtie < Rails::Railtie
config.to_prepare do
ApplicationController.send(:extend, ActsAsAwesome::Hook)
end
end
end
and the ActsAsAwesome::Hook code:
# lib/acts_as_awesome/hook.rb
module ActsAsAwesome::Hook
def acts_as_awesome(*args)
options = args.extract_options!
# do the things that make the controller awesome.
include ActsAsAwesome::InstanceMethods
before_filter :an_awesome_filter
end
end
I feel the concepts here are sound and have used similar processes before. Basically, it would tell Rails to execute the to_prepare block once during production and before each request in development (we want that because ApplicationController will be reloaded at those times, potentially wiping out our hook method); and the hook is just that: it adds a hook to all controllers (or rather, all controllers that extend ApplicationController) to allow the user to introduce the real "Awesome" code into their controllers without otherwise affecting controllers that don't need it.
The #acts_as_awesome hook doesn't, in itself, convey the Awesome functionality. That's because not all controllers might need this functionality. Instead, the method is responsible for introducing the real awesome stuff, via the ActsAsAwesome::InstanceMethods module. This way, the user only gets the Awesome functionality if they explicitly call the acts_as_awesome method. It also adds a before filter to the controller to demonstrate that the code in this method would be evaluated exactly the same as if it were in the target controller class itself.
This technique should work exactly the same if you're targeting models instead of controllers: just inject your hook into ActiveRecord::Base. As AR:B is only loaded at Rails boot, you should probably be able to put that into an initializer (refer to the Railtie docs), but I reserve the right to be mistaken here.
A gotcha concerning the railtie: the documentation reads as if it should have been autodetected, but I often have problems with this. To get around it, simply require the railtie from your gem's main source file (in the above example, that would be lib/acts_as_awesome.rb).
You can see the entire ActsAsAwesome source in all its glory at my github account:
http://github.com/sinisterchipmunk/acts_as_awesome
I hope this is helpful. Your question was somewhat high-level so a high-level response is the best I can do.
-Colin MacKenzie IV
http://thoughtsincomputation.com
#sinisterchipmnk

Whats the alternative syntax for ActiveRecord::RecordNotFound in Rails 3

With the introduction of ActiveModel in Rails 3 whats the new method of calling ActiveRecord::RecordNotFound. ActiveModel::RecordNotFound ?
This is the definition (1) of ActiveModel:
ActiveModel is a class to be implemented by each ORM to allow Rails to generate customized controller code.
ActiveRecord implements ActiveModel. ActiveRecord raises its ActiveRecord::RecordNotFound exception when it can't find record by given id or a set of ids (2) in the database.
This mean there can't be such exception like ActiveModel::RecordNotFound.
ActiveModel is a set of modules and conventions to be implemented, the main goal being providing a common interface to mappers, no more, no less. So nope, ActiveRecord::RecordNotFound stays ActiveRecord::RecordNotFound. RecordNotFound does not make sense for every mapper : with Mongoid for instance, you'll have DocumentNotFound (well, Mongoid::Errors::DocumentNotFound).