Rails custom field in to_json - ruby-on-rails

I have this code:
#locations = #list.all.to_json(:root => false,
:only => [:author,:lat,:long,:text])
It works great and is exactly what I want. But now I want to add to the fields an url for the show page of each entry.
So it would be like:
[{
"author:"blabla",
"lat":blabla,
"long":blabla,
"text":"blabla",
"url":"url for show page"
}]
I've tried merge option but it doesn't add anything or throw any errors.
How can I achieve this?

Why don't you add this field to a model (or whatever you called #list.all). For example:
class MyModel
def url
"/url/to/page/#{id}"
end
end
and in the controller just add a field to only array
#locations = #list.all.to_json(:root => false,
:only => [:author,:lat,:long,:text,:url])

Thanks to phts I was able to get a solution:
I defined the method in the model
def url
"/url/to/page/#{id}"
end
And in the options i added:
:methods => :url
And it worked.

You have an array after to_json, so there is no #merge:
#locations = #list.all.to_json(:root => false, :only => [:author,:lat,:long,:text]).collect do |l|
l.merge( {text: 'mytext',url: 'myurl'} )
end

Related

Pass arguments to ruby function in this context

disclaimer I am pretty new to Ruby / Rails
I am using RPH::Navigation for creating my navigation menus. What I am trying to do now is add some sub-nav items and I am doing so like this:
suboptions.each do |group|
def relpath
link(group[:link], group[:args]).
end
sub_menu.item group[:name], :path => :relpath
end
link is just a method that returns "#{link}?#{query_string}" where query_string is built from the args hash.
What I was originally trying to do was something like
sub_menu.item group[:name], :path => link(group[:link], group[:args])
but that put the return value in, and later it is called, returning a method not found error.
My current approach has the problem that group is not in scope within relpath. I tried also using Proc.new and lambda, but since those are not called like normal functions it chokes on them as well.
What can I do to correct this? What is the proper way?
EDIT
If I do
suboptions.each do |group|
def relpath(group)
link(group[:link], group[:args]).
end
sub_menu.item group[:name], :path => relpath(group)
end
Then the error I get is:
undefined method `mylink?myarg=1' for #<#<Class:0x007fd8068acd58>:0x007fd8068b07f0>
EDIT 2
Here is more extensive example of the code.
menu.item MyTestsController, :text => 'Test', :if => Proc.new { |view| view.can? :read, MyTest } do |sub_menu|
suboptions = [{:link => "tests", :name => "All Systems", :args => {:system_id => 0}},
{:link => "tests", :name => "System A", :args => {:system_id => 1}}]
suboptions.each do |group|
def relpath(group)
link(group[:link], group[:args]).
end
sub_menu.item group[:name], :path => relpath(group)
end
end
I have no experience with the navigation library in question, but looking at the documentation at https://github.com/rpheath/navigation it seems you are expected to give the name of a Rails named route helper as the path argument - not an actual URL route. The "undefined method" is simply generated because RPH::Navigation tries to call a helper method by the name that is defined in :path argument, and in this case Rails cannot find a named route helper method called "mylink?myarg=1". So basically, what you would need to do is to create a named route, and use that as the path.

how to put a link_to internal resource in a model with rails 2.3.x

I have a requirement to include internal links in a DataTables report. Therefore I must return the report data from Model#as_json, e.g.:
class Error < ActiveRecord::Base
include ActionView::Helpers::UrlHelper # provides link_to
include ActionController::UrlWriter # provides *_path
def as_json(options={})
{
:date => self.created_at,
:level => self.level,
:ip => self.ip,
:title => truncate(self.title, :length => 100),
:show => link_to('Show', error_path(self)),
:hide => self.handled ? "" : "#{link_to 'Hide', handle_error_path(self)}"
}
end
...
What an effort figuring out what I needed to include. But now I get error: "can't convert String into Hash"
This is because 'link_to' uses 'url_for' which is a method that both UrlHelper and UrlWriter both have which actually behave differently.
So I'm at my wits end. If someone can help me figure out how to do this, or show me how to fulfill the requirements without breaking MVC I will be very grateful either way.
Try creating the link manually:
:hide => self.handled ? "" : "<a href='/handle_error?params=something'>Hide</a>"
I will follow up my own question with what turned out to be the best solution: use the json_builder gem and keep your json in the view where it belongs :)

How to write a dynamic route in Rails 3?

I'm trying to write a generic route that will allow me to refer to it by the controller's action.
I'm using the following line:
match ':action' => 'pages#:action', :as => 'action'
let's say an action named `foobar' in the pages controller. I'd like to be able to write
link_to 'Click Me', pages_foobar_path
in a view. The problem is that I get the error Invalid route name: ':action' when I try to write that route.
Mind you, the line
match ':action' => 'pages#:action'
without the :as parameter works perfectly, but then I have to manually write the path, as such:
link_to 'Click Me', '/pages/foobar'
any way around that?
If dynamic means "recognize my actions when Rails starts up and generate routes dynamically":
It's not something that I would do, but it does what you want it to do without any redirection nor method_missing runtime overhead.
In config/routes.rb
controller_filenames = Dir.new("#{Rails.root}/app/controllers").entries
controller_filenames.each do |filename|
# you could restrict to only the pages_controller.rb on the next line,
# and in that case, you could simplify even more (see next example)...
if filename =~ /_controller\.rb$/
controller_name = filename.sub(/.rb$/, "")
controller_route_name = controller_name.sub(/_controller$/, "")
controller = controller_name.camelize.constantize.new
controller.action_methods.each do |action|
# if you don't want the controller name in your path match, just omit it...
match "#{controller_route_name}/#{action}" => "#{controller_route_name}##{action}", :as => "#{controller_route_name}_#{action}"
end
end
end
If you only want to do this for your pages_controller.rb file, then:
controller_name = "pages_controller"
controller_route_name = "pages"
controller = controller_name.camelize.constantize.new
controller.action_methods.each do |action|
# I've removed the controller_route_name from the match here...
match "#{action}" => "#{controller_route_name}##{action}", :as => "#{controller_route_name}_#{action}"
end
Now, if dynamic means "generate a route whenever I dynamically generate a new action":
You could really play with fire. Any of your existing actions can define new actions and routes. For example, I could define a route in config/routes.rb (but this could be any existing route):
match '/dynamic_define' => 'application#dynamic_define'
Couple that with a method in ApplicationController (again, this could be any existing action):
def dynamic_define
method_name = params[:mname]
self.class.send(:define_method, method_name) {
render :text => "output from #{method_name}"
}
Rails.application.routes.disable_clear_and_finalize = true
Rails.application.routes.draw do
match "/#{method_name}" => "application##{method_name}", :as => "application_#{method_name}"
end
render :text => "dynamic_define just created a new action named #{method_name}"
end
In your browser, you can visit:
/dynamic_define?mname=my_new_dynamic_action
# browser renders "dynamic_define just created a new action named my_new_dynamic_action"
And then visit:
/my_new_dynamic_action
# browser renders "output from my_new_dynamic_action"
I think you can get as far as:
link_to 'Click me', pages_path(:action)
by redirecting
match ':action' => 'pages#:action'
match '/pages/:action' => redirect(":action") # pages_path(:action) will match
This is less typing than the approach suggested in the first answer, but seems less expressive if anything.
I suppose you could override method_missing in your view class to catch pages_[stuff]_path and generate the proper string, e.g.
def method_missing(name, *args, &block)
if name =~ /^pages_[a-z]*_path$/
"/#{name.to_s.gsub!(/^pages_/,'').gsub!(/_path$/,'')}"
else
super
end
end
Forgive me if my method_missing knowledge or regex capabilities are lacking - hopefully this is helpful directionally at least.
If you write your route like that, the right way to access it is:
link_to 'Click me', action_path(:action => 'foobar')

ruby on rails and XML

I am trying to create a ruby on rails app to capture data from form and create a corresponding XML.I have created a dummy model class which is not extending active record
Do i have to do that .Below is the code and the error i m facing plz help
class RamOne
attr_accessor :name,:city
end
Controller
def start
#ramone = RamOne.new
end
def load_new
#ramone = RamOne.new(params[:ramone])
if #ramone.save
redirect_to :action => ‘gen_xml’
end
end
def gen_xml
#xml = Builder::XmlMarkup.new
#ramones = RamOne.find(:all)
render :layout => false
end
View captures name,city and has a submit action attached with load_new
error : wrong num of args(1 for 0 ) in load_new
what is wrong?
You can't call RamOne.new with an argument because your RamOne class does not override the initialize method. Also, #ramone.save and RamOne.find are all ActiveRecord methods, so I think you need to extend ActiveRecord::Base in your RamOne class.
Check out the Hpricot gem http://hpricot.com/ if you are doing some heavy duty XML.
Check out REST to clean up your controller. http://guides.rubyonrails.org/routing.html#restful-routing-the-rails-default
Can i get rid of the model class
and store my captured data in a normal ruby class and fetch from it to create the xml .Are there any helper methods available
similar to form_for() helper
<% form_for :ramone, #ramone, :url => { :action => "load_new" }, :html => { :method => :get } do |f| %>
can i find any other non ActiveRecordHelper methods
I dont want the Model class unnecesarily.

Rails Routing with Query String

I have a problem where I need values passed in from a GET request and I don't know how to set up the routing definition.
My Category object has a type(string),a color(string) and many products. I want to create a simple web service that lets the caller get all of a Category's products by passing in the Category's type and color:
http://www.myapp.com/getProducts?catType=toy&color=red
or ?
http://www.myapp.com/categories/getProducts?catType=toy&color=red
How do I define the correct routing for this situation? Are there better ways to do this in a Restful manner... because I know that Rails is Restful, so if there is a way to do it "correctly" then that would be even better.
Thanks
Your first example:
map.getproduct '/getProduct', :controller => 'your_controller', :action => 'your_action'
In controller you will have catType and color in params hash:
params[:catType]
=> 'toy'
params[:color]
=> 'red'
Is there better way? Probably yes, but it depends on your needs. If you will always have catType and color parameters, than you can add route like this:
map.getproduct '/getProduct/:catType/:color', :controller => 'your_controller', :action => 'your_action'
You will have access to those parameters with params hash like in previous example. And your urls will look like this:
www.myapp.com/getProduct/toy/red
If your parameters may change, you can use route globbing:
map.getproduct '/getProduct/*query', :controller => 'your_controller', :action => 'your_action'
Then it will catch all request that has www.my.app.com/getProduct/... at the begining. But you will have more work in controller. You will have access to query with this:
params[:query]
and for www.myapp.com/getProduct/color/red/catType/toy it will give:
params[:query]
=> ['color', 'red', 'catType', 'toy]
So you have to parse it manualy.
One RESTful way to to do this would involve a product resource nested beneath a category resource, like so:
http://www.myapp.com/categories/toy/products?color=red
Your routes.rb would need to contain:
map.resources :categories do |category|
category.resources :products
end
Since my url above using the Category's type attribute for routing, I'm implying that each type is unique, like an id. It'll mean that whenever you're loading a category in the Categories controller (or anywhere else) you'll need to load the category with Category.find_by_type(params[:id]) instead of Category.find(params[:id]). I like routing categories this way whenever possible.
Your ProductsController controller index action would find products using lines like:
#category = Category.find_by_type(params[:category_id])
#products = #category.products.find(:all, :conditions => { :color => params[:color]} )
Remember, your Category model must contain the line:
has_many :products
It's probable a good idea to enforce that in the model with validations:
validates_presence_of :type
validates_uniqueness_of :type
To make routing work you should also overwrite the to_param method in the Category model to return type instead of id:
def to_param
self.type
end

Resources