I'm converting an email template from Rails to Mandrill, the content for which requires a fair amount of data, some of which is nested through several associations.
Therefore, I'd like to pass objects via Mandrill's global_merge_vars, such as the (simplified) following:
[{ 'name'=>'order', 'content'=> #order.to_json(include:
{ user: { only: :first_name } },
methods: [:method1,
:method2,
:method3,
:method4])
}]
Which passes through to the mandrill template under the order variable similar to the following:
{"id":11,"number":"xxxx","item_total":"112.0"...
"user":{"first_name":"Steve"},"method1":"£0.00","method2":"£112.00",
"method3":"£112.00","method4":"£0.00"}
The problem is, I can't access anything within order (using Handlebars), i.e. {{order.id}}, {{order['id']}} etc. wont work.
It's not an option to break out data into a large number of variables, as some elements are collections and their associations.
I believe the problem occurs as everything is stringified when the variables are compiled for Mandrill -- therefore breaking the JSON object -- with the following a snippet of what is sent across:
"global_merge_vars"=>[{"name"=>"order", "content"=>"{\"id\":11,
\"number\":\"xxxx\",\"item_total\":\"112.0\"...
I can't seem to find any documentation / suggestions for dealing with this, so am wondering whether this it's possible to pass data of this nature, and, if so, how to correctly pass it to be able to access the objects in the Mandrill template. Any advice greatly appreciated!
Steve.
try this:
[{ 'name'=>'order', 'content'=> JSON.parse(#order.to_json(include:
{ user: { only: :first_name } },
methods: [:method1,
:method2,
:method3,
:method4]))
}]
Related
[EDIT] I am using the React and Rails differently and not using the react-rails gem...
Ok so i have my api written in Rails and it is formatted like this:
data: {
comments: [
{
comment: 'Lorem Ipsum',
user_id: 1
},
{
comment: 'dolor sit',
user_id: 2
},
{
comment: 'amet',
user_id: 3
}
]
}
now, in my react view, i want to have somewhat like, <%= User.find_by_id(params[:id]).name %>. What am I thinking is just to add posted_by attribute to table and add it as a key in api, having the string value of the user_id already set up with the controller(rails approach) and another one is to write another request(react approach) that will just fetch the name but i think its too much. What is the better approach?
In my opinion, it really depends on the numbers. You don't want to make, say, 15 requests if you have 15 comments on that page. My general proposing would be to keep this as close to JSON API as possible. However, if you want to stick to your current case, I would have two datasets:
1.Comments - which would be something like you have already
2.Users - Array of users, with all required fields (like name).
So that you would do only two requests initially.
Ok so this might be late. I just added a relationship between user and comments and added posted_by: Comment.user.name in the json response
I have an EmberJS filter like this:
/app/routes/trails/new.js
model: function (filterCurrentEmployees) {
return Ember.RSVP.hash({
trail: this.store.createRecord('trail'),
employees: this.store.query('employee', { status: '1,2'}).then(
function(data) {return data})
})
},
I was hoping that status: '1,2' would end up as a normal Rails param so I could do params[:status] and then filter the returned employees (you know so the db would get a query like 'where status IN ['1','2']')
But when this filter query is sent to Rails API I get this error:
ActiveModelSerializers::Adapter::JsonApi::Deserialization::InvalidDocument (Invalid payload ({:data=>"Expected hash"}): {"status"=>"1,2", "controller"=>"employees", "action"=>"index"}):
which occurs here in the controller:
api/app/controllers/employees.rb
def employee_params
ActiveModelSerializers::Deserialization.jsonapi_parse!(params)
end
but that is needed for AMS to work with Ember.
So I presume something is wrong with the way I am sending/creating the query in EmberJS?
It seems to be trying to make a GET collection request. Not sure really and this explains sort-of what is going on at the Rails end, but I don't know how to get Ember to create the filter properly so that AMS is happy to accept it.
EDIT - JSON-API Spec Reference
I was under the impression that AMS and Ember 2.7 with JSON-API 'just work out of the box'. I was actually expecting the Ember filter to comply with the spec and send
/employees?filter=status[1,2]
but it seems to not be doing that. AMS says the same thing here.
UPDATE
So with some pointers from the comments (thank you) I learned that the structure of the query hash might be incorrect. I also tried changing 'query' to filter but that then raises an actual Ember error:
The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page.
Now I don't know what the difference is between an Ember query and an Ember filter, perhaps a filter only runs on the client? Who knows, the docs are so sparse and so many questions on this are 1 or 2 years old.
So after much digging around for Ember Gold Nuggets, I found out that Controllers are STILL needed for...you guessed it...Query Parameters.
I've never used a Controller, and thought I never needed one.
So it seems I was basing my attempt at using query parameters on outdated information and code examples.
For those who run into this, the gold nuggets are here and here.
Also, it seems Javascript Object parameters as per JSON-API spec are not yet supported in Ember, according to this, although it's nearly a year old so do not know if that is still true.
UPDATE
So, after further gold mining, it seems I was confused and that Controllers are needed for Query Parameters in Ember on the client side, to assist the frontend application when it transitions from one route to another (and that is when you need a Controller to set them up).
But I want to just send a query parameter from within the Route code directly to the API, and examples of doing that are very hard to find.
So in the Rails Log I would expect to see BEFORE deserialization by ASM:
Rails.logger.info "Params are: #{params.to_json}"
something like this:
Params are:
{"data":{"filter":{"status["1,2"]}},
"controller":"employees","action":"index"}
ASM expects 'data' to be the root element of the hash, and then inside that I can place my filter. For example, from the Ember Route:
model: function () {
let myFilter = {};
myFilter.data = { filter: {status: ['1,2']}};
return Ember.RSVP.hash({
trail: this.store.createRecord('trail'),
employees: this.store.query('employee', myFilter).then(function(data) {return data})
})
},
I'm building an Rails app with a survey form which passes the responses as JSON format. Creation of answers works fine, however not quite sure how to approach the update.
Survey has got answers in the survey_answers table. Survey_answer has user_id, survey_id, question_id and response fields. That means however that every survey_answer is a separate record.
I can access the specific response through something like
SurveyAnswer.where(user_id: 1, survey_id: 1, question_id: 1).response
and update through that but then again, not sure how to handle it with JSON.
What do you think it's the best way to approach it?
Send the json to the Survey endpoint. Add accepts_nested_attributes for survey_answers to survey. Structure the json so that it looks like so:
{
survey: {
name: '',
survey_answer_attributes: [
{
...
},
{
...
}
]
{
}
White list the nested params. Basically RTFM.
I am currently in the process of making my first iphone app with a friend of mine. He is coding the front end while I am doing the back end in Rails. The thing is now that he is trying to send necessary attributes to me with a post request but without the use of a nested hash, which means that that all attributes will be directly put in params and not in a "subhash". So more specifically what I want to do is be able to retrieve all these attributes with perhaps some params method. I know that params by default contains other info which for me is not relevant such as params[:controller] etc.. I have named all attributes the same as the model attributes so I think it should be possible to pass them along easily, at least this was possible in php so I kind of hope that Rails has an easy way to do it as well.
So for example instead of using User.new(params[:user]) in the controller I have the user attributes not in the nested hash params[:user] but in params directly, so how can I get all of them at once? and put them inside User.new()?
I found the solution to my problem. I had missed to add the attr_accessible to my model which was what initially returned the error when I tried to run code like: User.new(params) having been passed multiple attributes with the post request.
The solution was very simple, maybe too simple, but since this is my first real application in Rails I feel that it might be helpful for other newbies with similar problems.
If you would like to just pass a more limited version of params to new, you should be able to do something like the following:
params = { item1: 'value1', item2: 'value2', item3: 'value3' }
params.delete(:item2)
params # will now be {:item1=>"value1", :item3=>"value3"}
Also see this for an explanation of using except that you mention in your comment. An example of except is something like:
params.except(:ssn, :controller, :action, :middle_name)
You can fetch the available attributes from a newly created object with attribute_names method. So in this special example:
u = User.create
u.attributes = params.reject { |key,value| !u.attribute_names.include?(key)
u.save
I'm trying to send a POST request from an external Ruby script to a Rails app via HTTP#post_form. The request is made to the create action (i.e. the URI is http://server/controller).
If I encode a single parameter into the request, everything is fine:
HTTP::post_form(uri, { :my_param => "value" })
Though I do have to explicitly pull out my_param from params manually, in the controller. This seems inefficient, and breaks creating a new record from within the app itself (because that parameter is not there). I'm consequently trying to make my script pose as Rails itself, passing the appropriate data as the controller would expect it, e.g.
HTTP::post_form(uri, { :object => { :my_param => "value" } })
However, this doesn't work. post_form seems to be escaping my hash into something different, i.e.
{ "object" => [\"my_param\", \"value\"] }
Which obviously doesn't do the same thing. Am I missing something obvious in the way I'm passing the data? Or can I not achieve what I'm after (creating a new record from outside the app)?
One straightforward way might be to simply imitate how Rails formats its parameters, like this:
params = { :my_param => "value", ... }
params = Hash[params.map { |key,value| ["object[#{key}]",value] } ]
HTTP::post_form(uri, params)
Edit: Well, look at that, I looked around a bit and found that Rails actually gives you a method to do the same thing using their own mechanism:
require 'active_support/core_ext'
...
HTTP::post(uri, parameters.to_param)
The to_param method will treat Arrays correctly, and everything else too. Notice that in this case you want to use HTTP::post, not post_form, since the parameters are already converted to a string.
I don't know much about post_form but the natural solution for me would be to use an ActiveResource object.
ActiveResource is available to ruby as well as to Rails. you use it just like you use a model only it posts and gets using XML
There is a Railscast on how this works here
http://railscasts.com/episodes/94-activeresource-basics
http://railscasts.com/episodes/95-more-on-activeresource
I think you'll find that this is a better fit for your requirements than post_form but as I say, I'm not familiar with post_form.