I'm using the RapLeaf API in a Rails app and when I call a RapLeaf record I get a response in JSON. How can I display JSON data using a Ruby method?
Here is the controller:
#user = User.find_by_id(params[:id])
#api = RapleafApi::Api.new('<MY_SECRET_API_KEY>')
Here is the view:
%td
= #api.query_by_email(#user.email)
Here is what it looks like when rendered in the page:
{"gender"=>"Male"}
I want to be able to call the gender this way
%td
= #api.query_by_email(#user.email).gender
But I get an undefined method `gender' for {"gender"=>"Male"}:Hash
What sort of method do I need to create to call gender using .gender?
Turns out that output data is a Ruby hash and not JSON. I've got to get my terminology strait.
Related
Is it possible to change the value in the Params hash when a Javascript function is called?
I have a hidden Div, say DIV1 that becomes visible based on the selected value in a select field, within DIV1, I have a readonly textfield whose value is set to a value returned by a helper method.
This helper method uses a dynamic find_by that depends on the value of Params,but I guess the param Hash doesn't change when the value of the select Changes (since it isn't a full page refresh?). Please, how do I Achieve updating this so that when the select Value changes, the new value is reflected in the params hash. I have :remote=>true in the form_for tag. Is there a better approach than mine?
The Select field in a rails view
#finance_year
<%=f.select :financeyear, options_for_select(finance_year),{ :include_blank => 'Select a
Financial Year' } %>
and a an onchange event for that select
jQuery ->
$('#finance').hide()
value = "Select a Financial Year"
$('#finance_financeyear').change ->
selected = $('#finance_financeyear :selected').text()
$('#finance').show()
$('#finance').hide() if selected is value
the helper Method
def amount_owed(student)
financeyear = params[:financeyear]
#thisstudent = Finance.find_last_by_user_id(#student.user_id,
:conditions => {:financeyear => financeyear } )
if(#thisstudent)
#amount_owed= #thisstudent.amount_owed
else
student.department.amount
end
end
I appreciate any help and I hope I've been able to ask the question intelligently.
The answer is AJAX.
First, we'll need to add a new route to config/routes.rb to make amount_owed() a true action:
get '/finance_years/amount_owed/:student_id/:financeyear' => "finance_years#amount_owed"
Next, we'll create a default view to be returned whenever the amount_owed() action is called:
/app/views/finance_years/amount_owed.html.erb
<%= #amount_owed %>
So, that part was easy. Now we need to edit the amount_owed action so it will work with our parameters:
/app/controllers/finance_years_controller.rb
def amount_owed(student)
financeyear = params[:financeyear]
#thisstudent = Finance.find_last_by_user_id(params[:student_id],
:conditions => {:financeyear => financeyear } )
if(#thisstudent)
#amount_owed= #thisstudent.amount_owed
else
#amount_owed = student.department.amount
end
end
This way, we can pass in the finance year and the student id from the params hash and get an amount_owed every time. Now, to give our coffeeScript access to the current student_id and finance_year variables, I'd add a couple hidden fields to the form in the view file:
/app/views/finance_years/_form.html.erb
<%= hidden_field_tag :student_id, #student_id %>
<%= hidden_field_tag :finance_year, #finance_year %>
The last trick is to edit the coffeeScript, firing an asynchronous GET request whenever the select box changes.
/app/assets/javascripts/finance_years.js.coffee
$('#finance_financeyear').change ->
student_id = $("#student_id").val()
finance_year = $("#finance_year").val()
selected = $('#finance_financeyear :selected').text()
$('#finance').show() unless selected == value
$.get "/finance_years/amount_owed/#{student_id}/#{finance_year}", (response)->
$('#finance input[type=text]').load(response)
And that's about all I can do being away from my rails development machine. Let me know if additional problems arise.
I'm not a rails expert, but you're not going to be able to modify server side code directly from javascript. You will need to make a call down to the server (either on a form submit or through an ajax request) to tell the server to update itself.
To clarify, the server code is responsible for the initial rendering of the page, but once the template has been rendered it doesn't exist on the client page. So you can't directly modify it from coffeescript/javascript. You need to send a request back to the server to handle that.
I'm trying out angular JS and I want to get data from a nested resource defined in my rails application.
I wrote the following lines:
UserMission = $resource("/users/:user_id/user_missions/:id", {user_id: "#user_id", id: "#id"}, {update: {method: "PUT"}})
$scope.user_missions = UserMission.query()
and I get the following error:
Processing by UsersController#show as JSON
Parameters: {"id"=>"user_missions"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", "user_missions"]]
Completed 404 Not Found in 10ms
ActiveRecord::RecordNotFound (Couldn't find User with id=user_missions):
app/controllers/users_controller.rb:100:in `current_resource'
app/controllers/application_controller.rb:34:in `authorize'
My rails routes are organized like so:
resources :users do
resources :user_missions
end
I think it comes down to me not understanding "#id". It says it comes off of the "data object" from the angularjs site and I am not exactly sure what that means.
Any help would be appreciated thanks.
Update
Another question. I have not found any examples of rails with angularjs using nested resources (an example User has_many :missions, through: :user_missions ) with $resource. Is there a good example of angularjs manipulating nested resources (with $resource) with ajax?
Read through my answer to your previous question, you should include the values for both the parameters in an object you pass as a parameter in the call, i. e.:
$scope.user_missions = UserMission.query({user_id: some_value, id: some_other_value});
I was also looking for a way to handle nested resources with ngResource. I am not familiar with how rails works or what your data looks like but this is what I had:
{"num_results": 5, "objects": [....], "page": 1, "total_pages": 1}
I needed to reach in and grab the nested objects array for the query action. Using the 1.0 version of angular this is not possible. However, with the 1.1 version (I tested with 1.1.3) it is possible to do this.
In my controller I just setup the resource like this:
$scope.MyModel = $resource("/api/mymodel/:id",
{},
{'query': {method: 'GET', isArray: true, "transformResponse": function (data) {
return JSON.parse(data).objects;
}}});
The key here is the transformResponse function passed as part of the action config. In 1.1 any extra config items in the action config are passed down into the $http config for the request. The $http service allows a transformResponse function that can manipulate the data returned by the request. Using this function I can reach into the nested structure and return the array I need for the action.
One caveat to notice here is that the transformResponse function receives a string value, so you must first parse the data into what you are expecting. The other caveat is that you return the actual final data value you want, NOT a string. Even though you receive a string value you should return the end data value required.
The "data object" refers to your instance objects ($scope.user_missions is an array of those objects -- or would be rather, if you actually managed to successfully retrieve it), and you can think of UserMission as being the class.
If you call the query method on the class object (UserMission), in your case, it requires at least one parameter in order to know which User's UserMission(s) to retrieve.
UserMission.query({user_id: <USER_ID>});
The above would perform a "GET ALL"
To obtain a specific UserMission ( "GET ONE" ), you would have to supply both IDs
UserMission.query({user_id: <USER_ID>, id: <MISSION_ID>});
Makes sense?
I have a Rails application where user parameters are all provided via a RESTful API with JSON parameters. Specifically, there is no client-side HTML form from which the user posts data: it's raw JSON.
So to create a new Car entry, the user might:
POST www.mysite.com/api/car
model=Ford&year=2012
In my app, by the time I receive this, the Action Pack values are intermingled with the user values in the params[] hash, so I get:
params = {:model=>"Ford", :year=>"2012", :format=>"json", :action=>"create", :controller=>"api/cars"}
What's the best way to separate the user-generated parameters from parameters generated by Action Pack? The best I can think of is to delete the latter:
car_params = params.reject {|k,v| [:format, :action, :controller].member?(k)}
car = car.new(car_params)
but that doesn't smell right. Is there a better way? (For example, can I get Action Pack to encapsulate the user supplied params into a single hash and pass that as a single element of params[]?)
Don't know if it can help, but I'd just create a method in application_controller :
def user_params
return params.reject {|k,v| [:format, :action, :controller].member?(k)}
end
So throughout the code, you can just use user_params when you don't want ActionPack params
I'm building a web service app and I'm trying to handle nicely a 422 page sending back to the user the JSON the POSTed to better debug the error. To do this, I use request.request_parameters which get me back the JSON I sent, but it happens to be organized (for me) in a wired way and I can't really get it back only with the original data
What I send as JSON is this.
{
"name":"New set intensity",
"properties":
[
{"uri":null,"value":"on"},
{"uri":"https://type.lelylan.com/properties/intensity","value":"100.0"}
]
}
What I get from request.request_parameters is this.
{"{\"name\":\"New set intensity\",\"properties\":"=>{"{\"uri\":null,\"value\":\"on\"}, {\"uri\":\"https://type.lelylan.com/properties/intensity\",\"value\":\"100.0\"}"=>{"}"=>nil}}}
My main problem is that somehow the content becomes the key, and this recursively inside. Is there a way to get back the clean data? Thanks a lot.
UPDATE: I'm trying to better understand where and why this problem occurs.
In my controller I tried to access in the two available ways I know.
#Â request.body.read.inspect
"{\"name\":\"New set intensity\",\"properties\":[{\"uri\":\"not_valid\"}]}"
# request.request_parameters
{"{\"name\":\"New set intensity\",\"properties\":"=>{"{\"uri\":\"not_valid\"}"=>{"}"=>nil}}}
The request is made from Capybara
page.driver.post(#uri, #params.to_json)
The controller returns only JSON so this is the way I defined it. I din't put 'respond_to' and 'respond_with' and when I make the request it renders the json view show.rabl.json. This makes me think that it recognize the correct format.
class FunctionsController < ApplicationController
before_filter
...
def index
...
end
def show
..
end
def create
body = JSON.parse(request.body.read)
#function = Function.new(body)
if #function.save
render 'show', status: 201, location: FunctionDecorator.decorate(#function).uri
else
render_422 "notifications.resource.not_valid", #function.errors
end
end
Thanks.
I'm trying to learn how to query a rails database and return the results as JSON. In my example, I want to query the data using the parameters, city and state.
So far, in my controller, I have gotten the following action to work.
def state
#bathrooms = Bathroom.where("state = ?" ,params[:state])
respond_to do |format|
format.json { render :json => #bathrooms }
format.js { render :nothing => true }
end
end
This is also my routing entry.
match '/bathrooms/state/:state',
:controller => "bathrooms",
:action => "state"
I can call this resource with the following URL:
http://localhost:3000/bathrooms/state/CA.json
That's all good but I don't know how to query by more than one parameter. Adding and AND clause in the controller seems to be easy enough.
BUT....I don't know how to
a.) Correctly write the routing entry?
b.) What would the URL look like if I tested it in a browser?
I've tried to understand rake routes but I must be missing something.
Could someone provide a basic example for what the action should look like? What the routing entry should look like and what does the URL to access the resource look like?
Again, if written in SQL, this is what I would like to be returned.
SELECT * from bathrooms WHERE city='Chicago' AND state = 'IL'
Any help appreciated.
You don't have to pass everything by the route - the URL also support GET parameters - those are the parameters you usually see after the question mark in the URL. You can add those GET parameters without changing your routes: http://localhost:3000/bathrooms/state/IL.json?city=Chicago. Then your can access the city parameter via params[:city]. but in your case, I think it will be better to use http://localhost:3000/bathrooms/index.json?state=IL&city=Chicago. You'll also need to change your routing to
match '/bathrooms/index',
:controller=>:bathrooms,
:action=>:index
and put the code in the index method of BathroomsController. You access the parameters the same - but the concept is different - you don't enter a state and look for bathrooms by city, you just look for bathrooms by state and city.
Anyways, you don't want to write the URL by hand - you want to a Rails helper or an HTML form generate it:
link_to "bathroom in Chicago, IL",:controller=>:bathrooms,:action=>:index,:state=>'IL',:city=>'Chicago'
If you want to use a form(to let the users choose their own state and city), you need to set it's method to GET:
form_tag {:controller=>:bathrooms,:action=>:index},:method=>:get do
and put state and city as fields.
It's also worth noting that while you can use SQL's AND to perform a search by multiple fields, you can also chain where methods: Bathroom.where(:state=>params[:state]).where(:city=>params[:city]).
You can put any arbitrary parameters in your querystring.
For example:
http://localhost:3000/bathrooms/state/CA.json?city=Chicago
your query looks like this:
#bathrooms = Bathroom.where("state = ? and city= ?" ,params[:state], params[:city])