Including reopened class inside controller - ruby-on-rails

I want to add custom methods to the Recurly::Account class by reopening it, and then use it in my controller.
something like this:
#reopen class
class Recurly::Account
#my custom method
def my_meth_1
end
end
class MyController
def index
account = Recurly::Account.find( ... ) #gem method
account.my_meth_1 #my custom method
end
end
In which file should I reopen the Recurly::Account class and how should it be included in my controller?

I think lib folder is a good place for this.
Simply create a file like this
# lib/recurly.rb
class Recurly::Account
def my_meth_1
end
end
how should it be included in my controller?
You will probably need to turn on autoloading from lib, see this topic how to do it Rails 3 autoload. After that, you can call it directly from controller.

Related

Call a rails method from a class outside of MVC pattern

I'm creating a news feed application that consumes an XML feed for later use.
I am struggling to get the app to call a method I have written inside of a class outside of the default Rails folders. How can I load this class into the app for use in a controller (for example)? I've read a bunch of questions on SO, resulting in the following structure / code.
My understanding is that with the following I shouldn't need to require 'fetch_feed.rb' from the controller or place anything in the lib folder. I am however getting the following error:
NoMethodError (undefined method `fetch_news' for FetchFeed:Class):
app/controllers/v1/news_items_controller.rb:18:in `index'
I am trying to call a method from the FetchFeed class
Folder Structure
- app
- controllers
- retrievers
- fetch_feed.rb
fetch_feed.rb
class FetchFeed
def fetch_news
// Code here
end
end
aplication.rb
module FeedReaderApi
class Application < Rails::Application
config.autoload_paths += %W(#{Rails.root}/app/retrievers)
// Other code
end
end
news_item_controller.rb
class V1::NewsItemsController < ApplicationController
def index
FetchFeed.fetch_news
end
end
Any help much appreciated.
Should be:
FetchFeed.new.fetch_news
fetch_news has been defined as an instance method. So you need an instance of FetchFeed to call the fetch_news method.
To make FetchFeed.fetch_news work, define it as a class method like below:
class FetchFeed
def self.fetch_news
// Code here
end
end
OR
class FetchFeed
class << self
def fetch_news
// Code here
end
end
end

In Rails, where to put useful functions for both controllers and models

Suppose I have a function trim_string(string) that I want to use throughout my Rails app, in both a model and a controller. If I put it in application helper, it gets into the controller. But application helper isn't required from within models typically. So where do you put common code that you'd want to use in both models and controllers?
In answer to the specific question "where do you put common code that you'd want to use in both models and controllers?":
Put it in the lib folder. Files in the lib folder will be loaded and modules therein will be available.
In more detail, using the specific example in the question:
# lib/my_utilities.rb
module MyUtilities
def trim_string(string)
do_something
end
end
Then in controller or model where you want this:
# models/foo.rb
require 'my_utilities'
class Foo < ActiveRecord::Base
include MyUtilities
def foo(a_string)
trim_string(a_string)
do_more_stuff
end
end
# controllers/foos_controller.rb
require 'my_utilities'
class FoosController < ApplicationController
include MyUtilities
def show
#foo = Foo.find(params[:id])
#foo_name = trim_string(#foo.name)
end
end
It looks like you want to have a method on the String class to "trim" itself better than a trim_string function, right? can't you use the strip method? http://www.ruby-doc.org/core-2.1.0/String.html#method-i-strip
You can add new methods to the string class on an initializer, check this In Rails, how to add a new method to String class?
class String
def trim
do_something_and_return_that
end
def trim!
do_something_on_itself
end
end
That way you can do:
s = ' with spaces '
another_s = s.trim #trim and save to another
s.trim! #trim itself
but check the String class, it looks like you already have what you need there

Add rails route helpers to a class as class methods

How can i add rails route helpers like "root_path" to a class like my_model.rb as a class method?
So my class is like this:
Class MyModel
def self.foo
return self.root_path
end
end
MyModel.foo
The above doesn't work because Class MyModel doesn't respond to root_path
This is what I know:
I can use include Rails.application.routes.url_helpers, but that only add the module's methods as instance methods
I tried doing extend Rails.application.routes.url_helpers but it didn't work
Please feel free to school me :)
URL routes shouldn't generally need to be accessed from a model. Typically you should only need to access them from your controller when handling a request, or when rendering a view (if you're e.g. formatting a link URL).
So instead of asking your model object for the root path, you would simply call root_path from within your controller or a view.
Edit
If you're just interested in the reason why you're unable to include the module's method as class methods in your class, I would not expect a simple include to work, since that would include the module's methods as as instance methods in your class.
extend would normally work, but in this case it does not due to how the url_helpers method is implemented. From actionpack/lib/action_dispatch/routing/route_set.rb source
def url_helpers
#url_helpers ||= begin
routes = self
helpers = Module.new do
...
included do
routes.install_helpers(self)
singleton_class.send(:redefine_method, :_routes) { routes }
end
The included block containing the routes.install_helpers(self) call indicates that you will need to include the module in order to get the methods install (so extend is out).
The following should work if you call extend in the class context. Try this:
Class MyModel
class << self
include Rails.application.routes.url_helpers
end
end
Class.root_path

How to make a method available to all controllers? And how to all models?

I am new to Rails and have written a method to_csv which I have put it in products_controller.rb, but I want it to available to all other controllers too. What is the preferred way to do that? Is it in application.rb?
Similarly, if I am writing a method in some model.rb, how to share that method between all the models?
application_controller will be the place. If for model, maybe you can write in a module, then
include in your model which you want to use.
1) Try ActiveRecord::Base monkeypatching.
The initializer directory is a best place to collect all those little task
So, try /config/initializers/active_record_extension.rb,
class ActiveRecord::Base
def self.export(parameters)
#your csv logic goes here
end
end
or
2) create master class, which is used to inherit by all active_record model
for example /models/your_class.rb
class YourClass < ActiveRecord::Base
def self.export(parameters)
#your csv logic goes here
end
end
class CsvDB < YourClass
end
You can also create a separate model without inheriting from ActiveRecord::Base and define your csv method in that particular model. And from any controller just call
model_name.method_name(parameters)
For example, in the model CsvDB:
class CsvDB
def export(parameters)
# your csv logic goes here
end
end
From any controller just call
CsvDB.export(parameters)

Display a Variable from a Method in a File in the /lib/ directory on a View in Rails

In a file called foo.rb in my /lib/ directory it reads:
module Foo
def some_method
#text_1 = "Hello!"
end
end
How can I get the results of this method to show up in a View?
I've seen that I need to include the following line in the /config/application.rb file:
config.autoload_paths += %W(#{config.root}/lib
However, I do not completely understand how to pass a variable from a module in a file saved in the /lib/ directory - to show up in a View. I appreciate any advice.
In order to get that value to show up in the view, you'll need to understand how modules are used in Ruby. Typically modules are mixed into other classes either by including or extending them. This would then make that method available to another class which could then be referenced in the view. In your case you might want to include it so it becomes available to instances of whatever class you put it in. Say you have an ActiveRecord model called MyClass and you include Foo. You can then call my_method on instances of that model as demonstrated below:
class MyClass < ActiveRecord::Base
include Foo
end
In your controller:
class MyController
def new
#my_class = MyClass.new
end
end
In your view:
#my_class.some_method
Having said all that, it seems like there might be a better way to do whatever it is you're trying to do :)
Yes.I agree with
Beerlington.
You can do it in an other way,
It is not mandatory to add config.autoload_paths += %W(#{config.root}/lib to application file.Because by default the files which are located in /lib directory won't be executed at first when we run an application using rails s.
In order to make those files to be loaded,we need to include that line in application.rb.
Otherwise,we can directly write it as below,
In model,
require 'Filename'
class MyClass < ActiveRecord::Base
include Foo
end
In controller,
require 'foobar'
class BuyerController < ApplicationController
include Foobar
end
In foobar.rb,
module Foobar
def Foobar.foobar
"Hello world!"
end
end
In view,
<%= Foobar.foobar %> (You can directly call the method by using Modulenmae.Methodname)

Resources