Two optional values in the attribute of the helper methods in rails - ruby-on-rails

I have created a helper method for generating a li content tag with a link
def method1(attribute,path,classname={},id={})
content_tag(:li, link_to(attribute, path,:class => classname),:id => id)
end
I am calling the helper method like
<%= method1("BLOGS",blogs_path,"","blog1")%>
In the above case I gave an empty string for class as there is no need for class here, but other places need that.
But if I use an empty string for class , then "blog1" becomes the class ..
How can I resolve this?
I am working on rails 2.3.11

Look into options hashes. This is used just about everywhere in Rails and is perfect for handling clunky method invocations like that.

Agree with the other answers. Your method definition should be more like
def method1(attr, path, options={})
content_tag(:li, link_to(attribute, path,:class => options[:classname]),:id => options[:id])
end
Then you can specify what you want to pass. On the downside, i seem to remember that rails sets the classname to the id if there is no classname passed in

Related

Ruby: metaprogramming methods based in model attribute

I'm trying to expose some methods to a class based on the values in its order attribute, which can be something like ['top', 'bottom', 'right', 'lower-right'].
First, my class deletes from that array anything that responds blank like so:
def order
order.split(' ').delete_if do |o|
send(o).blank? if respond_to? o
end
end
After that, I want to "expose" top (for example's sake) as a method for the class. I've tried stuff like this in the initialize method:
order.each do |o|
V1_ATTRIBUTES << o.to_sym
define_method(o) do |a|
send(a).blank? ? '' : send(a)
end
end
But o isn't defined when the class isn't instantialised, a la:
<NameError: undefined local variable or method `o' for #<Class:#<APIDocument:0x007fb8123609f8>>>
Anyone have any success with a better way to get this result?
Note: I know it's not great practice allowing the user to write instance method names, but in this case security and breakages aren't a concern.
You can define singleton methods (per-object methods).
def order
orders.split(' ').map{|o| send(o)}.compact.each do |o|
singleton_class.send(:define_method, o) do
send(o).to_s
end
end
end
But as you can see, this only messes up your code. So don't abuse metaprogramming, use it wisely.

Rails create a helper to add text

I have a fee column in my model and it is an integer type, so I try to create a tiny helper to add a dollar sign neatly in front. Which means, instead of writing:
span = "$#{#object.fee}"
I can write something like
span = #object.fee.dollar
So I created the tiny helper.
module ApplicationHelper
def self.dollar
"$#{self.try(:to_s)}"
end
end
I am not sure where to put it, so basically it's now showing
undefined method `dollar' for 180:Fixnum
number_to_currency()
Rails 4.2 has this ActionView::Helper
number_to_currency(1234567890.506)
Helper
If you want to implement this as a helper, this works
module ApplicationHelper
def dollar(amount)
amount = number_to_currency(amount)
end
end
Invoke
<%= dollar(your_var_here) %>
Rails spec for number_to_currency()
http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_to_currency
Note: Other versions of Rails may have this function, you'd have to check your version.
module ApplicationHelper
def dollar(amount)
"$#{amount}"
end
end
and then:
span = dollar #object.fee
I think it's because you're in a helper, so you can't refer to self.
You can do it in your Model, or in the helper do :
def print_dollar(your_value)
Or, you can also use : number_to_currency(dollar, :unit => "$"), which will render it the way you want.
Hope it help
Your helpers are included in the view context, so you need two changes:
def dollar - because it's included in the renderer, you don't need self
Call it as dollar(#object.fee) - it's not included on the object, but in your view. If you want to call it as #object.dollar, declare the method in whatever class #object is.
Additionally, the number_to_currency helper already exists and is quite robust. Perhaps you want to use that.

How to use plain Ruby object with url helpers

I am rendering a page from a simple custom model (not ActiveRecord, plain ActiveModel) and I cannot get the url/path helpers to generate an url with their id, like this:
person_path(model)
# I want: /person/3
# I get: /person
Is there any concrete class I must inherit or function to implement so the url helpers work with my custom model?
I heard about to_param but it is not working, at least not with this:
class Person
include ActiveModel::Model
def id
3
end
def to_param
id.to_s
end
end
According the documentation that should work:
Any class that includes ActiveModel::Model can be used with form_for,
render and any other Action View helper methods, just like Active
Record objects.
But I guess there is still a missing function needed for the url helpers to work
You need to define a persisted? method that returns true: the default implementation always returns false, which causes rails to generate a path with no id.
It would be good if you can share the code from config/routes.rb or at least the result from rake routes.
Double check your routes again. I think you may have defined the route as a singular resource resource :person which will not add an ID to the url.

Using Decorator pattern in Rails but can't access view helper

I'm trying to implement Decorators using the learnings from "Rails 4 Patterns" Code School course, but I'm running into trouble as I need a view helper in the Decorator class.
I want my view to have:
<%= #model_decorator.previous %>
Then in the decorator:
def previous
if object.prev_item.nil?
"Previous"
else
link_to("Previous", object)
end
end
The course suggests you make a call to the decorator within your view helper in the view file itself, but that's no good if the logic could output one result with a helper and one without. (i.e. need the output to be a link or not).
I've tried using helpers.link_to but it errors out as not providing the correct information for the url_for option. I've confirmed link_to("Previous", object) works within the view itself.
For Rails 4
include ActionView::Helpers::UrlHelper
link_to("Previous", Rails.application.routes.url_helpers.send("#{object.class.name.underscore}s_path".to_sym, object))
As for me it`s better to make a decorator for it:
class LinkDecorator
include ActionView::Helpers::UrlHelper
def initialize(label, object)
#label = label
#object = object
end
def show
link_to(label, url_helpers.send("#{object.class.name.underscore}s_path".to_sym, object))
end
def index
link_to(label, url_helpers.send("#{object.class.name}s_path".to_sym))
end
...
private
attr_reader :label, :object
def url_helpers
Rails.application.routes.url_helpers
end
end
Example usage:
LinkDecorator.new(object.name, object).show
If I understand your problem correctly, you essentially want links in a plain old ruby object.
My solution would be this:
include ActionView::Helpers::UrlHelper
link_to("Previous", Rails.application.routes.url_helpers.objects_path(object))
# assuming the object is always of one class
If the object is of a different class, than it would be possible to use the .send method to send the correct message to app ie.:
include ActionView::Helpers::UrlHelper
link_to("Previous", Rails.application.routes.url_helpers.send("#{object.class}s_path".downcase.to_sym, object))
# I'd create a function out of that line to make it a bit neater
It sounds like the error thrown by url_for comes from missing the routes and there's a few ways to include those. My solution kinda avoids that problem by using Rails.application.routes.url_helpers. Hope this helps!

Rabl.render: how to use view helper methods?

I'm using Rabl to generate XML output in a rake task:
xml = Rabl.render #listings, 'feeds/listings', :format => :xml
# do stuff with xml
However, I need to use multiple helper methods in the rabl view file referenced, and I keep getting a NoMethodError as I expected from the answer to this question.
I tried using extends and include in the class used by the rake task but I still get the same error on the helper methods:
require "#{Rails.root}/app/helpers/feeds_helper.rb"
class SerializeData
extends FeedsHelper
def perform
xml = Rabl.render #listings, 'feeds/listings', :format => :xml
# do stuff with xml
end
end
My question is: is there any way to use helper methods in rabl view files generated in this way? (or at least in a way that I can still render them as a string in a rake task?) The helper methods are used many, many times to correctly format various data per fixed requirements, so it would be very difficult to remove them entirely.
I ended up with a monkey-patchy solution.
I noticed that the NoMethodFound error came from an instance of the Rabl::Engine class, so I included the needed routing and helper methods in that class and was then able to access them:
require "#{Rails.root}/app/helpers/feeds_helper.rb"
...
class Rabl::Engine
include Rails.application.routes.url_helpers
include FeedsHelper
end
Also note that the URL host needs to be set if using url in addition to path helpers (e.g. root_url and root_path):
Rails.application.routes.default_url_options[:host] = "www.example.com"
I would definitely prefer a non-monkey-patch solution or at least one where helpers could be included as needed depending on the controller of the action rendered. I'll wait to accept this to see if anyone can come up with such an answer.
You can pass in a scope object with the scope parameter. So if you have access to an object with the helper included, like when in the view context, then you can pass that
eg:
<%= Rabl::Renderer.json(object_to_render, 'api/v1/object/show', view_path: 'app/views', scope: self).html_safe%>
So outside of the view context you'd need to pass in a custom object with the helpers included to make this clean.
eg
class RakeScope
include FeedHelper
end
Rabl::Renderer.json(object_to_render, 'api/v1/object/show', view_path: 'app/views', scope: RakeScope.new() )
I've not tried the second option but the first works great.
While not quite the same problem, I had a similar problem accessing helpers from RSpec specs. I created a helper function that creates a scope that you can use to add whatever helpers you need. The following gave me access to the path and url helper methods and something similar should work for Rake.
#spec/support/rabl_helper.rb
def render_rabl(object, options={})
options = {
format: 'json',
view_path: 'app/views',
file: example.example_group.top_level_description,
scope: RablScope.new
}.merge(options)
result = Rabl.render(object, options.delete(:file), options)
options[:format] == 'json' ? JSON.parse(result) : result
end
class RablScope
include Rails.application.routes.url_helpers
end

Resources