Rails accessing json object in javascript - ruby-on-rails

var errorList = "<%= object.errors.messages.to_json %>";
In the above code object.errors.messages stores the Hash value as shown below.
{
:username => [
"can't be blank",
"is too short (minimum is 8 characters)"
],
:first_name => [
"can't be blank"
],
:last_name => [
"can't be blank"
],
:email => [
"can't be blank",
"is invalid"
],
:secondary_email => [
"can't be blank",
"is invalid",
"has already been taken"
],
:password => [
"can't be blank"
]
}
I want to access this hash value in javascript as a json object so that i can access each error messages conveniently (for ex errorList.username, errorList.first_name etc).So i am trying to convert that hash value into json and assign it to the errorList variable.So that i can access the error messages(for ex errorList.username, errorList.first_name etc).
<%= object.errors.messages.to_json %>" /*here i am trying to convert hash value into json
But i am not able to do that using above code, tell me the errors in that code if any, Otherwise tell me how can i access the hash value in ruby as a json in javascript.
Thank You.

You are passing the json as a string, javascript has no idea it is json. Also, the string is not html_safe, so ruby will try to escape it. You need to tell rails it is safe and parse it:
var errorList = JSON.parse("<%= object.errors.messages.to_json.html_safe %>");
However this is not the best way to do this. There is a very nice gem called gon. It allows you to pass ruby variables to your javascript easily and will move this logic from your view to your controller.
# controller
gon.errorList = object.errors.messages
# javascript
gon.errorList #=> {"username": ["can't be blank", ....], ...}

Related

Gibbon::MailChimpError (the server responded with status 400 #title="Invalid Resource"

I am trying to use gibbon gem and following their github docs. Here is the code I have
class ChimpController < ApplicationController
def create
send_to_mail_chimp ( params[:email])
end
def send_to_mail_chimp(email)
puts "send email is #{email}"
gibbon = Gibbon::Request.new(api_key: "bla")
gibbon.timeout = 10
gibbon.lists('e61cf2454d').members.create(body: {email_address: email, status: "subscribed"})
end
end
<%= simple_form_for :email, url: newsletter_path, :method => :post do |f| %>
<%= f.input :email, input_html: {class: 'form-control', placeholder: 'enter email'} %>
<% end %>
The exact error message is
Gibbon::MailChimpError (the server responded with status 400 #title="Invalid Resource", #detail="The resource submitted could not be validated. For field-specific details, see the 'errors' array.", #body={"type"=>"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/", "title"=>"Invalid Resource", "status"=>400, "detail"=>"The resource submitted could not be validated. For field-specific details, see the 'errors' array.", "instance"=>"", "errors"=>[{"field"=>"email_address", "message"=>"Schema describes string, object found instead"}]}, #raw_body="{\"type\":\"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/\",\"title\":\"Invalid Resource\",\"status\":400,\"detail\":\"The resource submitted could not be validated. For field-specific details, see the 'errors' array.\",\"instance\":\"\",\"errors\":[{\"field\":\"email_address\",\"message\":\"Schema describes string, object found instead\"}]}", #status_code=400):
app/controllers/chimp_controller.rb:10:in `send_to_mail_chimp'
app/controllers/chimp_controller.rb:3:in `create'
The error message you're getting back is telling you exactly what the problem is:
{
"field": "email_address",
"message": "Schema describes string, object found instead"
}
You're passing the email in as a javascript object (ruby hash) instead of a string. All you need to pass is the raw email address.
I think you need to give the members method a MD5 hash of the lower case email address (via the mailchimp subscriber management). Try
def send_to_mail_chimp(email)
puts "send email is #{email}"
gibbon = Gibbon::Request.new(api_key: "bla")
gibbon.timeout = 10
md5_email = Digest::MD5.hexdigest(email['email'].downcase)
# I prefer 'upsert' to 'create' but should work with either
gibbon.lists('e61cf2454d').members(md5_email).upsert(body: {email_address: email['email'], status: "subscribed"})
end

Dynamic subject in Mandrill e-mail using rails

I have passed dynamic content to the body of the email. But looking at the API docs the subject params only accepts a string and not an array.
Is there a way to pass a dynamic subject? I would like to pass the name of the recipient in the subject
I have the following right now:
m = Mandrill::API.new ENV['MANDRILL_APIKEY']
message = {
:subject=> template.subject,
:from_name=> template.name,
:from_email=> template.from + "#" + email_domain,
:to=>mails,
:global_merge_vars=> [
{ :name => 'IMAGE', :content => image_tag},
],
:html=>email_template,
:preserve_recipients => false,
:merge_vars => variables,
}
It seems that Mandrill reads merge variables in the subject as well. So it is as simple as adding *|SOME_VAR|* in your subject text and then passing it as a parameter in the merge_vars.
More details here.

nesting another field in a json column with a rails form

I'm trying to use the Json type available in the Postgres 9.2 release as a means to store a variety of data in one field. I created a column called data of json type on the corrections table. The form is a regular rails form except that the number of form fields it creates depends on the length of a #content array like this
<%= f.fields_for :data, #correction.data do |d| %>
<% #content.each do |content| %>
<%= d.text_area content, :class => 'content', :value => "", :cols => "40", :rows => "2", :id => 'correction_data_'"#{content.parameterize}"%>
<% end -%>
<%= end %>
If the #content array, had two elements, the database entry for data would look like this
data: {"key from #content"=>"value entered in form field", "key from #content" => "value entered in form field }
I have two questions
1 How would I change the Rails form to nest another key value pair inside (or associate with) each key value pair
"key from #content"=>"value entered in form field"
For example, I'm wondering if there's a way to nest or associate a comment field inside this data column for each key/value pair like this
"key from #content"=>"value entered in form field" comment key => comment value
"key from #content"=>"value entered in form field" comment key => comment value
2 Is this proper JSON format? It seems to me like it's just saving a bunch of key value pairs with the key always changing depending on the content from #content. If it isn't, is that a problem? Am I missing out on something by doing it this way?
data: {"content from #content"=>"value entered in form field", "content from #content" => "value entered in form field }

How do I convert an array of strings into a comma-separated string?

I have an array:
array = ["10", "20", "50", "99"]
And I want to convert it into a simple comma-separated string list like this:
"10", "20", "50", "99"
array.join(',') will almost do what you want; it will not retain the quotes around the values nor the spaces after.
For retaining quotes and spaces: array.map{|item| %Q{"#{item}"}}.join(', ')
This will print "\"10\", \"20\", \"50\", \"99\"". The escaped quotes are necessary assuming the question does in fact call for a single string.
Documentation on the %Q: string literals.
You could use inspect as suggested in another answer, I'd say that's personal preference. I wouldn't, go look at the source code for that and choose for yourself.
Useful aside: array.to_sentence will give you a "1, 2, 3 and 4" style output, which can be nice!
["10", "20", "50","99"].map(&:inspect).join(', ') # => '"10", "20", "50", "99"'
Here:
array.map {|str| "\"#{str}\""}.join(',')
Several answers have offered solutions using #map, #inspect, #join. All of them fail to get certain details of CSV encoding correct for edge cases involving embedded commas and/or string delimiters in the elements.
It's probably a better idea to use the stdlib class CSV then to roll your own.
irb> require 'csv'
=> true
irb> a = [10,'1,234','J.R. "Bob" Dobbs',3.14159]
=> [10, "1,234", "J.R. \"Bob\" Dobbs", 3.14159]
irb> puts a.to_csv
10,"1,234","J.R. ""Bob"" Dobbs",3.14159
The map.join solutions are sufficient if this encoding doesn't need to care about embedded delimiters, or is intended for some internal representation only, but they will fail if generating data for exchange with other programs that expect Comma Separated Values (CSV) as a generally understood representation.
The simplest solution is to use the built in ".to_sentence" method.
So
["fred", "john", "amy"].to_sentence outputs "fred, john, and amy"
This is a slightly alternative solution, particularly handy if you need to convert an array with double quoted strings to a single quoted list (for say SQL queries):
"'#{["John Oliver", "Sam Tom"].join("','")}'"
to
'John Oliver', 'Sam Tom'
Attribution: https://alok-anand-ror.blogspot.com/2014/04/ruby-join-array-elements-with-single.html
This is how you can send push notifications using FCM for Android devices.
Assuming you want notify followers when ever a user posts something on their status this is how you do it. This is done in Rails 5.2.6 for Rest Apis--- But still you can use the same for web push notifications. This is for sending to many devices with registration_ids to target followers with notifications.
Gem : fcm
in your controller:
require "fcm"
def create_vibe(user)
#vibe = user.vibes.new(content: #content, picture: #picture, video: #video, isvideofile: #isvideofile, video_thumbnail: #video_thumbnail, source: #source, background_color: #background_color)
#followed = user.followers
if #followed.present?
#registration = #followed.map { |s| s.registration_id }
end
if #vibe.save
fcm = FCM.new("") # set your FCM_SERVER_KEY
options = {
data: {
notification_type: 1,
title: "#{#vibe.user.username} " "has posted a new Vibe",
body: "#{#vibe.content}",
user_data: {
vibe_id: #vibe.id,
user_id: #vibe.user.id,
background_color: #background_color,
},
},
}
response = fcm.send(#registration, options)
puts response
render :status => 200,
:json => { :success => true,
:info => "Vibe posted successfully",
:vibe_info => {
:content => #content,
:picture => #picture,
:video => #video,
:video_thumbnail => #video_thumbnail,
:isvideofile => #isvideofile,
:source => #source,
:fcm => options,
} }
else
render :status => 200, :json => { :success => false, :result => "Vibe can't be blank" }
end
end

What is the best way to test export to excel or csv using rspec?

I'm using ruby CSV library to export reporting data from Ruby On Rails application.
And i am wondering what would be the best way to test such operation?
Thanks in advance
Hi I was using Ruby 1.9.2 which has Faster CSV, but the concept should be similar. I actually have my factories in a helper method, but put it all together to make it easier to see here. I'd also love to know if there is a better way, but this worked for me.
I generated the report, and then opened it to compare it with my expected results. I wanted to make sure the file existed. You could do something similar without actually saving the file.
describe "Rsvp Class" do
created = "#{Time.now.to_formatted_s(:db)} -0800"
before(:each) do
[{:first_name => "fred", :last_name => "flintstone", :state => "CA", :zip => "12345", :created_at => created},
{:first_name => "barny", :last_name => "rubble", :state => "CA", :zip => "12345", :created_at => created}].each do |person|
rsvp = Factory.build(:rsvp)
rsvp.first_name = person[:first_name]
rsvp.last_name = person[:last_name]
rsvp.state = person[:state]
rsvp.zip = person[:zip]
rsvp.created_at = person[:created_at]
rsvp.save
end
end
it "should generate a report csv file" do
response = "first name, last name, email, address, address line 1, city, state, zip, variation code, tracking code, created at\nfred, flintstone, fred#example.com, , , , CA, 12345, , , #{created}\nbarny, rubble, fred#example.com, , , , CA, 12345, , , #{created}\n"
Rsvp.generate_report
string = ""
CSV.foreach("#{::Rails.root.to_s}/reports/rsvp_report.csv", :quote_char => '"', :col_sep =>',', :row_sep =>:auto) do |row|
string << "#{row.join(", ")}\n"
end
string.should == response
end
end

Resources