Get user attributes using user_id - Rails w/ React - ruby-on-rails

[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

Related

Rails - How to use bulk import with action text?

I am building a rails 6 app and I am stuck on an issue.
Let's say I have a table tasks which has 3 fields:
id
state
description
The description field is in fact a rich_text field thanks to ActionText.
My problem is that I have a csv file composed of 3 columns (id, state, description) and, during initialization of the app, I want to populate my database with it, using bulk import.
Normally, if description was a normal column, I would do something like this:
Task.insert_all(
# My csv converted in array of hashes [{state: YY, description: ZZZZZZZ}]
)
But as description is not really an attribute of the table tasks, it won't work. How can I still use bulk import to import large set of data, but still use action_text fields?
Right now, I am forced to use "one by one" insertions which takes a very long time!
Thank you for any leads you can bring.
I think the easiest way to do this is by splitting your input like this:
# Tasks
tasks = { id: XX, state: YY, ... }
# Descriptions
descriptions = { record_type: 'Task', record_id: XX, name: 'description', body: 'Actual body' }
Then you can do something like this:
Task.insert_all(tasks)
ActionText::RichText.insert_all(descriptions)
Is this what your are looking for?
========================================================
Update:
Just to clarify how this works, we need to understand that RichText model works as any other model in Rails, but serializing the information as showed here: https://github.com/rails/rails/blob/master/actiontext/app/models/action_text/rich_text.rb#L11
To see what is really being extracted from the database we can use the helper *field*_before_type_cast. For example:
descriptions = [ { record_type: 'Task', record_id: XX, name: 'description', body: '<p>EXAMPLE</p>' } ]
ActionText::RichText.insert_all(descriptions)
ActionText::RichText.last.body => <ActionText::Content....>
ActionText::RichText.last.body_before_type_cast => '<p>EXAMPLE</p>'
Also, keep in mind that you can have one rich text per record (is a 1 - N polymorphic association). So, if you try to insert a second description for your Task it won't work

Ruby: Hash: use one record attribute as key and another as value

Let's say I have a User with attributes name and badge_number
For a JavaScript autocomplete field I want the user to be able to start typing the user's name and get a select list.
I'm using Materialize which offers the JS needed, I just need to provide it the data in this format:
data: { "Sarah Person": 13241, "Billiam Gregory": 54665, "Stephan Stevenston": 98332 }
This won't do:
User.select(:name, :badge_number) => { name: "Sarah Person", badge_number: 13241, ... }
And this feels repetitive, icky and redundant (and repetitive):
user_list = User.select(:name, :badge_number)
hsh = {}
user_list.each do |user|
hsh[user.name] = user.badge_number
end
hsh
...though it does give me my intended result, performance will suck over time.
Any better ways than this weird, slimy loop?
This will give the desired output
User.pluck(:name, :badge_number).to_h
Edit
Though above code is one liner, it still have loop internally. Offloading such loops to database may improve the performance when dealing with too many rows. But there is no database agnostic way to achieve this in active record. Follow this answer for achieving this in Postgres
If your RDBMS is Postgresql, you can use Postgresql function json_build_object for this specific case.
User.select("json_build_object(name, badge_number) as json_col")
.map(&:json_col)
The whole json can be build using Postgresql supplied functions too.
User.select("array_to_json(array_agg(json_build_object(name, badge_number))) as json_col")
.limit(1)[0]
.json_col

Sending object as a variable to Mandrill via Rails

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]))
}]

Best way to update Rails model with JSON

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.

Mongoid OR query syntax

This must be asked alot but it is very poorly documented. There is no mention at http://mongoid.org/en/mongoid/docs/querying.html
I'm trying to check whether a user exists (below is an AND query), how can I change it to an OR type query
Username.where(:username=>#username, :email=>#email)
(Either the email or the username must match).
I have found some pretty complicated ways online including sending a direct javascript (from): http://omarqureshi.net/articles/2010-6-17-using-or-in-mongoid
Surely there must be a simple clear syntax to do this correctly?
For the sake of others who end up on this page, the updated syntax is now
Username.or({username: #username}, {email: #email})
Please refer to the updated docs or relevant impl.
Yeah, this used to be documented better. Try this:
Username.any_of({:username => #username},
{:email => #email})
There is a typo in #miguel-savignano's response. According to Stackoverflow the "edit queue is full", which is why I didn't submit an edit.
Proper syntax:
Username.or({username: #username}).or({email: #email})
A more concise solution:
Username.or({username: #username}, {email: #email})
The Mongo selector will resolve to:
{"$or"=>[{"username"=>#username}, {"email"=>#email}]}
I found this question as I was trying to solve for creating "or" queries.
If you are looking to match a string or any one of an array of elements, then you will need to write a Mongoid query with the Mongo '$in' selector.
For example, you have a specific username and an array of emails. You would like to return all results where at least one of the fields matches either the username or one of the emails within the array.
#username = "jess"
#emails = ["hi#mail.com", "test#mail.com", "foo#mail.com"]
User.or({username: ""}, {email: {'$in': #emails}})
The Mongo selector will resolve to:
{"$or"=>[{"first_name"=>""}, {"email"=>{:$in=>["hi#mail.com", "test#mail.com", "foo#mail.com"]}}]}
If you have Users with 2 of the 3 emails in your database, then the selector will return a count of 2.
If you have a User with the username "jess" and 3 additional Users each with one of the given emails, then the selector will return a count of 4.
Also, in Mongoid 5.0, if you still want to use the where method, use the following
Username.where('$or' => [ { username: #username }, { email: #email } ])
this is very useful when you are building a kind of query hash in a dynamic way and you need to keep the where method
In Mongoid 5.0, this works for me
Username.or({username: #username}).or({email: #email})

Resources