Saving json response in create - ruby-on-rails

I want to save a json response but it is saving the title instead of the value. Also having issues with how the params are coming through with slashes instead of as a hash
I have the following response from form submit:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2134", "shipping_rate"=>{..."shipping_rate"=>"{\"serviceName\"=>\"USPS First Class Mail - Package\", \"serviceCode\"=>\"usps_first_class_mail\", \"shipmentCost\"=>2.66, \"otherCost\"=>0.0}"}, "commit"=>"Create Shipping rate"}
form:
...
<% #rates.each do |rate| %>
<%= form.radio_button :shipping_rate, rate.as_json %> <%= rate %><br />
<% end %>
...
I am under the impression using as_json removes the "/" so it comes through as a hash parameters.
I also tried using #rates.as_json.each with same results
Create method in controller:
#shipping_rate.service_code = params["shipping_rate"]["shipping_rate"]["serviceCode"]
How the service_code saves is as "serviceCode" and not "usps_first_class_mail".
How can I:
Have the params come through as a hash, without the /'s
Save the value of params["shipping_rate"]["shipping_rate"]["serviceCode"] instead of the title

rate.as_json is correctly returning a hash, but when you pass data to form.radio_button it get's converted into something html friendly. Basically, form.radio_button calls .to_s (or some similar method that probably also escapes html) on that hash, which is why you're getting the hash as a string.
As a rule, individual HTML form elements should not contain hash data, and especially not ruby formatted hash data. Keep in mind that once the page is rendered in a browser, it knows nothing about the backend, let alone how to run ruby code.
You should take a step back and think of this RESTfully. If your users are meant to select a rate, and you have a number of rate records in your db, you really only need them to send back the id of the rate they would like. Without seeing your controller it's hard to tell exactly what else would need to change, but your radio buttons should probably look more like:
<%= form.radio_button :rate_id, rate.id %>
Your controller's create method would then be responsible for setting the user's selected rate, possibly requiring you to look up the rate again.

Related

Why is my ruby object being converted to a Hash after saving it in a session and how do I retain it's status as an object?

I have an instance of a Board class that I am saving into a session. After I submit a form and try to retrieve the Board object from the session, the session[:board] is now a hash. It is probably easier to demonstrate then explain so here is my code.
the new method in my controller:
def new
session[:player] = "X"
session[:board] = Board.new
#board = session[:board]
end
Here is the view:
<div id="board">
<%= simple_format(#board.render) %>
</div>
<h2>Choose the column you would like to drop a piece in</h2>
<%= form_tag( drop_piece_path, :method => "post" ) do %>
<% 7.times do |col| %>
<%= label_tag col %>
<% unless #board.column_full?(col) %>
<%= radio_button_tag(:column, col) %>
<% end %>
<% end %>
<%= submit_tag("Enter move")%>
<% end %>
<%= #board.class %>
At this point #board.class is a Board like I expect it to be.
After I submit the form to the following drop_piece method:
def drop_piece
#board = session[:board]
#board.drop_piece(params[:column].to_i, session[:player])
save_session(#board)
end
I get this error:
undefined method `drop_piece' for #<Hash:0x007fe40bd070e0>
And #board.class and session[:board].class both result in Hash. And drop_piece is a method of my Board class so it makes sense that I can't call it on a Hash.
So somewhere along the way my Board object is being converted to a hash.
Maybe I am just misusing sessions, but I tried googling the issue already and was not able to come up with anything. Thanks for the help.
You're not meant to stuff random objects into a Rails session. Sessions are essentially a key-value store of strings, so what you're seeing is automatic flattening of objects into a form that the session can manage.
You're better off converting your object to JSON before passing it to the session and decoding it after retrieving it. In your situation, you could also just create a constructor that takes all necessary fields of your Board object as parameters and reconstruct the Board within the receiver method or use Ruby's Marshal module to get what you want.
You can also store your Board in something more persistent (cache or even database) and just pass an ID to your session. The receiver can then retrieve the row based on ID and reconstruct the object.
When you use the cookie session store (the default), the default behaviour since rails 4.1 is to serialize session data using JSON. Earlier versions of rails used Marshal, which did allow storing of arbitrary ruby classes, but a number of ruby security vulnerabilities involving marshal made people wary of using this. You are also of risk of bugs when a newer version of an application loads data created by an older version.
You can revert to the old behaviour by setting
Rails.application.config.action_dispatch.cookies_serializer = :marshal
Or by using a different session store. However I would recommend that you instead stick to storing simple data in the session, or at the very least be explicit about what is stored rather than letting this conversion happen implicitly.

How i can get attributes from non persisted object to persisted object in rails

I have an application that consumes a webservice, load an object not persisted in the database (I get via JSON and turn it into ruby object). How do I send attributes of this object to the creation form. A new object with reference to this object received via webservice to be created.
I want to click a button "add new" take it attributes, and add these attributes to the attributes of the new object to be persisted in the database.
How can I do this?
Grateful.
After you have received the attributes from the api as JSON and parsed it into a Ruby Hash, you can just throw that into Model.new. For example, you could do in the controller action of the first page, where the API request is made:
attrs = JSON.parse(api_response_body)
#=> {"title" => "foobar"}
#article = Article.new(attrs)
#=> #<Article title: "foobar">
I understand you want to get the API response in one request, then use the values obtained in the next request to actually persist the values to the database. You will thus need to keep track of the values between the requests. A simple way to acheive that would be using a form with hidden fields on the first page:
<%= form_for #article do %>
<%= f.hidden_field :title %>
<!-- more hidden fields here... -->
<%= f.submit 'New Article from API Result' %>
<% end %>
Then, you can simply re-use the #create action for your resource as normal without making any modifications to it. You will also get all of your validations, strong parameters etc for free.

Using API in partial and passing values?

I am trying to display some info from an API.
I have this code:
<% recco = Model.find_by_id(activity.trackable.id %>
Now, rendering the following line will output the ID I want:
<%= recco.item_id %>
However, when I want to link to this item and I need the name from the API, some of the code fails and some not. This is the line I have:
<%= link_to #client.author(recco.item_id).name, book_path(recco.item_id) %>
The book_path works and displays a link to the correct URL with the ID. The client that tries to get the name from the API returns that it is not found.
But, if I try remove the the recco.item_id and just hardcode it to:
<%= link_to #client.author("7").name, book_path(recco.item_id) %>
It works and displays the author name. Is there a special reason for the API request to not understand that the recco.item_id is a number? The book_path displays the link just fine.
It looks like the author method expects a string instead of an integer. All you have to do is add to_s to the item_id for it to work:
<%= link_to #client.author(recco.item_id.to_s).name, book_path(recco.item_id) %>
The reason why the API does not understand the integer you passed to it is likely because they did not logic have in that method to convert that passed argument into a string. Ideally, a public would try and convert whatever args are passed to it into the type of value it expects. The to_s we did on your method would ideally be in the API, but since you likely don't have control over the API code, you'll have to do the workaround yourself which doesn't take much effort anyway. :)

How it's possible to send an array from one view to the next

I have a Controller with the function getAccounts where I look for certain accounts. My idea is to first show the number of results and then send the result array to the next function called showAccounts which generates the view. First of all I declared the result array as an instance variable. Then I tried to send with a form tag. It does not work ... Has anyone an idea?
def getAccounts
filter = '(uid='+params[:id]+')'
attrs = ['*']
#accounts=Array.new
conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn=admin, dc=cippool-mb, dc=rwth-aachen, dc=de','DLPins!')
conn.perror("bind")
begin
conn.search($base, $scope, filter, attrs) { |entry|
setAttributes(entry)
}
rescue LDAP::ResultError
conn.perror("search")
exit
end
conn.perror("search")
conn.unbind
end
def showAccounts
end
The view where I send the data.
Es wurden <%= #accounts.size %> Accounts gefunden.
<%= form_tag :action => "showAccounts" do %>
<%= hidden_field_tag "accounts", #accounts %>
<%= submit_tag "Anzeigen" %>
<% end %>
I can also paste the view where I need this array, but I dont't think it's relevant for this question. I use Rails 3.2.7 and Ruby 1.9.2p0
If you want to pass some large amount of data between separate requests I would suggest using session, it's designed for such things.
If you debug(#accounts) you'll see what it passes -- something like <#0x7187237 Array> which is not what you want!
If you really want to pass in the accounts array, you'll need to serialize it to a text format to put in a hidden field. That's going to probably be a HUGE chunk of data though if #accounts is large.
That said, you could dump it to YAML or JSON, or use one of the serialization functions in Ruby or put it into a custom text format of your own (not recommended). Keep in mind then that you need to deserialize on the next page before you use it.
I'm assuming part of the wanting to pass it to the next step is to avoid an expensive LDAP request. You might want to look at putting in a lightweight cache -- redis for example -- to temporarily store the requests.

rails form using database

i have a rails form ive made in which the form fields are extracted from the database. i did it like this because for different products, there are different form fields. i could have made one big order form to do it, and if the product field didnt apply to the product it would be left blank, but it seemed like making the fields being called from a database made more sense because there are 30-40 fields per order. anyways the error in which im running into is when im extracting the row field_type, it prints out the literal value instead of putting it in rails. heres what it looks like:
<% #form_field.each do |field| %>
<p>
<%= "f.#{field.field_type}" %> #this prints out f.text_field
</p>
<% end %>
Instead of printing out f.text_field, i would like it to actually make a text field. I tried using raw but no look seeing as thats for html. is there a way to do this in rails?
You'd need to build up the string and send it to f, like f.send(field.field_type) (untested) along with any arguments needed for that particular form field type.

Resources