working with custom hash array in Rails - ruby-on-rails

I already posted a similar question but i got told to try and solve it myself and post here what i have so far.
What i'm doing is calling some xmlrpc methods to extract some data from an external app.
what i can do so far is display contents from a simple array as per below.
<% #attachment.each do |att| %>
<div class="item">
<%= image_tag att %>
</div>
What i want is to be able to pass a hash array similar to this:
{id:"1", content:"somedataaa", imgurl:"someurl.com/image.jpg"}
what i want is when the user clicks on an image to pass the id to a controller method so i can then go and get more data with the id provided and provide another view.
<% #hasharray.each do |att| %>
<div class="item">
<%= att.id %> //this could be hidden an only used to pass the id to a method
<%= image_tag att.url %> //add a link_to here somehow to route to a method on the controller.
</div>
I know how to do this with rails model data, but since this data is coming from an external xmlrpc i have to pass it as a hash array.
Could you please guide me to how i need to do this, is this the right way, or can i parse the hash array and somehow save it to a Rails model so i can then use the view as normal and have access to the routes.

attachments = [{ :id => 1, :url => 'images/1.jpg' }, { :id => 2, :url => 'images/2.jpg' }]
attachments.each do |attachment|
link_to image_tag(attachment[:url]), "/path/to/controller/#{attachment[:id]}/show"
end
Side note: Please follow proper naming conventions. Don't name variables "hasharray" or "hash" or "array" or anything similar. Make them meaningful. Please.
Reading this will help: http://www.ruby-doc.org/core-1.9.3/Hash.html

You can just pass the hash instead of a model, and us att[:id] instead of att.id.
If you really need it to be a model instead of a hash, you can look at Hashie, which provides several methods to convert a hash to a model:
https://github.com/intridea/hashie

Related

Pass a PORO from view to controller

What would be the best way to pass a Plain Old Ruby Object that I have in a view to a controller method?
It is not an object that is persisted in the DB. I would rather not refactor things and just want some ideas on best way to pass this object.
view
link_to "activate", activate_apis_path(my_ip_instance: #my_ip), class: "btn btn-primary btn-xs"
controller
#my_ip = params[:my_ip_instance]
#my_ip is just a string... want the whole object
(Rails 4.2)
Usually the best way is through a form. Consider creating a form with hidden fields for all of your #my_ip attributes.
<%= form_tag activate_apis_path do %>
<%= hidden_field_tag "my_ip_instance[foo]", #my_ip.foo %>
<%= hidden_field_tag "my_ip_instance[tomato]", #my_ip.tomato %>
<%= submit_tag "Activate", class: "btn btn-primary btn-xs" %>
<% end %>
(Extra credit: you could also loop over #my_ip's attributes to generate the hidden fields.)
Another way is to serialize #my_ip as JSON and then deserialize it in the controller. I think that is much messier though.
link_to "activate", activate_apis_path(my_ip_instance: #my_ip.to_json)
To make this work for a more complex object, you would need to write your own serializer/deserializer logic into the class as described in this post.
require "json"
class A
def initialize(string, number)
#string = string
#number = number
end
def to_json(*a)
{
"json_class" => self.class.name,
"data" => {"string" => #string, "number" => #number }
}.to_json(*a)
end
def self.json_create(o)
new(o["data"]["string"], o["data"]["number"])
end
end
What you basically need to do is to serialize the object. Rails provides built in options to serialize objects and Object.to_query which can be used to convert to query parameters.
But, passing around a bunch of state like that violates rest and is indicative of a poor application design. If it's a non-persisted object it should be passed as form parameters in a POST/PATCH request. In a GET request you should strive to initialize all objects needed from the headers, params from the request url and session.

ruby on rails search form

I'm new to RoR and I've managed to make a basic search form but keep getting errors when trying to expand the search tags (name).. I have a model with various data (location, website, email, telephone) and was wondering how I can add these to my current search code.
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
static_pages_controller.rb
def home
#ciirs = Ciir.search(params[:search])
end
/home.html.erb
<%= form_tag ciirs_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag " Search Database Records ", :name => nil %>
</p>
<% end %>
When clicking the submit button (no search terms) the url is:
ciirs?utf8=✓&search=
but when modifying the name condition to something like 'website' the url changes to
ciirs?utf8=✓&search=&commit=+Search+Database+Records+ –
Since you mentioned you are new to RoR, I must share the way I learned RoR was reading, using and analyzing one issue at a time. I would suggest you to take a look at following points one at a time and try & learn how RoR treats them and how these fit your question:
How form_tag works?
How text_field_tag works?
Once you have understood form_tag, difference between text_field_tag and f.text_field?
How params objects are created, and it uses names of form controls?
How and when to use GET and/or POST form methods? Inadvertently, what are different types of method and when to use them?
How URL are used in the form_tag and what components are they made of?
Sprinkle a bit of knowledge of Ruby language by learning between Arrays and Hashes? In fact, learn Ruby as much as you can.
Answering your question,
/home.html.erb
<%= form_tag "/static_pages/home", :method => 'post' do %>
<p>
<%= text_field_tag "search[name]", params.has_key?("search") && params[:search].has_key?("name") ? params[:search][:name] : "" %>
<%= submit_tag " Search Database Records " %>
</p>
<% end %>
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ["name LIKE '%?%'", search[:name]])
else
find(:all)
end
end
So I modified your form, and told RoR about search params containing data for name.
params is a Hash (which is a key-value pair) having key named search, which further is a Hash having key named name.
The same principle is followed in the model code. We passed the Hash of key search to the function and in there, used the value of key named name.
I also updated the url in form_tag, to point it to home action of your controller. Assuming that you have added it to your routes.rb file, it usually follows the pattern controller_name/action_name or the function name action_name_controller_name_path or action_name_controller_name_url. Run rake routes command at your root directory to list out all paths in your application.
Also note, I used POST method instead of original GET. You may wish to use GET here, so please change it back.
I hope this works.
I found no error in your code. the url changed to ciirs?utf8=✓&search=&commit=+Search+Database+Records+ is normal. submit_tag generates a button named "commit" defaultly, it will be parsed in the params. I see you add :name => nil , it will fix the problem, the other part of your code needn't to be modified. I copied your code and tested it, it ran smoothly.

Pass Parameters in Link_to

I would like to pass a parameter through a link_to method in Rails. I know there is a way to do it via the URL but I really don't want to do that. Is there any way to pass a param via a link without adding it to the link itself?
I know in PHP you can post and then retrieve that value by using the post variable. Is there something similar in Rails?
link_to signature looks as follows:
link_to(body, url_options = {}, html_options = {})
So, POST would look like (lets say you want to POST user's data):
link_to "Link text", some_path(:foo => "bar", :baz => "quux"), user: #user, :method => :post
User's data can be retrieved in the controller using params[:user]
Here's how you can pass a parameter around via the link_to method in order to, say, create a new object with the passed parameter. This strategy would allow you to pass variables among actions in your controller and create objects with predefined attributes:
Say in your show view, you have a variable called #foo that you want to pass to your new controller action. In which case, in your show view, you can have
<%= link_to "Link Text", new_widget_path(:foo => #foo) %>
which would store #foo in params[:foo], allowing you to use params[:foo] in your controller. Which controller action you get directed to depends upon *new_widget_path*. In this case, you get directed to the new action in WidgetController.
Clicking on Link Text will direct Rails to the new action of your WidgetController. You can have
def new
#widget = Widget.new(:foo => params[:foo])
end
Then, in your new.html.erb view file, you can allow the user to create a new Widget object with this pre-defined foo attribute already filled out via a hidden form field:
<%= form_for(#widget) do |f| %>
<%= f.label :other_attribute %><br />
<%= f.text_field :other_attribute %>
<%= f.hidden_field :foo %>
<%= f.submit %>
<% end %>
Allowing the user to create a new widget with the foo attribute already filled out!
Passing information through a web request can be done either by the URL: http://example.com/foo?bar=blah in a GET request which is what link_to does, or through a POST operation which usually requires a form. The form could have hidden elements if you just want a submit button:
<form method="POST" action="http://example.com/foo">
<input type="hidden" name="bar" value="blah">
<input type="submit">
</form>
There are various rails helpers to help build the form if needed.
Lastly, if you really want a link, you could either CSS style that button, or you could use javascript to observe a link and then POST the info. (the method Simon Bagreev posted does this with javascript)
What sort of parameter? If it's a key for a GET request, convention would dictate using the url (e.g. params[:id] or a an active record path variable). If you want to POST something, you should be using a form. Otherwise, you could write a helper method to set a session variable or something, but think about your architecture and what you're semantically trying to do, and I'm sure someone here can help you out.

How can you pass an object from the form_for helper to a method?

So let's say I have a form which is being sent somewhere strange (and by strange we mean, NOT the default route:
<% form_for #form_object, :url => {:controller => 'application',
:action => 'form_action_thing'} do |f| %>
<%= f.text_field :email %>
<%= submit_tag 'Login' %>
<% end %>
Now let's say that we have the method that accepts it.
def form_action_thing
User.find(????? :email ?????)
end
My questions are thus:
How can I make the object #form_object available to the receiving method (in this case, form_action_tag)?
I've tried params[:form_object], and I've scoured this site and the API, which I have to post below because SO doesn't believe I'm not a spammer (I'm a new member), as well as Googled as many permutations of this idea as I could think of. Nothing. Sorry if I missed something, i'm really trying.
How do I address the object, once I've made it accessible to the method? Not params[:form_object], I'm guessing.
EDIT
Thanks so much for the responses, guys! I really appreciate it. I learned my lesson, which is that you shouldn't deep-copy an object from a form, and that the parameters of a form are actually included when you submit it.
I will admit it's sort of disheartening to not know stuff that seems so obvious though...
you need to pass the "id" of your "#form_object" in the url and then lookup that object (assuming you have a model and using ActiveRecord)
It depends on how do you set up your routes. If you're using the default /:controller/:action/:id route, you can pass it as a parameter in the URL. Note that not the whole #form_object can/should be passed, but it's id or some other attribute to identify it instead. In this case, you should make your URL:
<% form_for #form_object, :url => {:controller => 'application',
:action => 'form_action_thing', :email => some_email} do |f| %>
<%= f.text_field :email %>
<%= submit_tag 'Login' %>
<% end %>
And in your controller
def form_action_thing
#user = User.find_by_email(params[:email])
end
You can pass parameters through the url, but when submitting a form the only thing that should (probably) be passed through the url is the record id for a RESTful record.
And it appears you didn't find out yet where your form data can be found in the params.
So
All the data from your form should end up in params[:form_object]. The actual value for :form_object is selected by Rails, it's probably coming from the object's class (too lazy to look that up right now)
In any case, you can easily find out where your form values are submitted by looking at your console/log output. All the params for each requests are dumped there.
The form fields will be inside the params like params[:form_object][:email] - each field that is submitted has an entry corresponding to the field name.
The params hash not contain all the original values from your #form_object. There will be only those values that you included in the form.
If you need to pass non-editable values to the controller with your form, use hidden_field(s) These will be submitted with the form, but are not visible to the user.

Missing template

so i have this code:
<% form_tag(:action => 'find') do%>
Product name:
<%= text_field("cars_", "name", :size => "30") %>
<input type ="submit" value="Find"/>
<%end%>
upon pressing the button I want it to complete the method (def find) found in the controller but its requesting the html.erb file:
Template is missing
Missing template cars/find.erb in view
path H:\Documents and
Settings/owner/My
Documents/NetBeansProjects/RailsApplication5/app/views
in the find def (found in controller)
def find
#car = Car.new(params[:car_])
end
What is the last line of your find method? Generally, if you don't specify the template to render in your controller method, Rails attempts to find a template with the same name as the method. That is why it is saying it can't find cars/find.erb. Without seeing the code in your find action, it is hard to give a better answer.
Your find method should be doing some searching, not initializing with the parameters. I recommend checking out something like thinking sphinx or searchlogic if you want to do searching.
I believe that your code is executing the find action. However, after it finds the car object, it needs to write that into a template that shows the results of your search. By convention, rails looks for a file called find.html.erb in the view folder for that controller. So, the error message you are seeing means that Rails has executed the line of code in your action and is now trying to generate some HTML to send back to the browser
If you create a simple file in the view folder for that controller with contents:
<%= #car.name %>
You should see the results.
However, your code is a bit confusing to me as I don't know why a find method would create a new Car object. I would expect something like this:
def find
#car = Car.find_by_name(params[:name])
end
I would also expect that your form would be more like:
<% form_tag(:action => 'find') do%>
Product name:
<%= text_field_tag("name", :size => "30") %>
<%= submit_tag "find" %>
<%end%>

Resources