Sending Simple Email in Rails - ruby-on-rails

I've read a few questions and http://guides.rubyonrails.org/action_mailer_basics.html on how to send emails with Rails but can't seem to get it to work within the context of my current application.
I had an existing emailer.rb with a couple of methods that were identical apart from the parameters they accepted were named differently so I copied their format:
def quotation_notification(q)
#recipients = q.recipient_email
#from = q.partner_name + "<#{q.partner_email}>"
#subject = "New Quotation from " + q.partner_name
#body[:q] = q
end
I then created a new view file in emailers named quotation_notification.rhtml which just contains text for the moment.
I am then calling the function from inside a different controller and sending hardcoded parameters for now:
q = QuotationEmail.new(:recipient_email => 'martin#domain.co.uk', :partner_name => 'Martin Carlin', :partner_email => 'martin#domain.co.uk')
# send email
Emailer.deliver_quotation_notification(q)
Then finally, I created a new model for QuotationEmail
class QuotationEmail
def initialize(recipient_email, partner_name, partner_email)
#recipient_email = recipient_email
#partner_name = partner_name
#partner_name = partner_email
end
end
The error I get is ArgumentError (wrong number of arguments (1 for 3))
Eventually I'll be sending more parameters and hopefully attaching a pdf aswell but just trying to figure out why this isn't working first.

You are getting this error because while initialising QuotationEmail object though you think you're passing 3 params you're essentially passing only one parameter which is a hash. And initialize is expecting 3. See example below
class A
def initialize(a,b=1,c=2)
puts a
puts b
puts c
end
end
a = A.new(:recipient_email => 'martin#domain.co.uk', :partner_name => 'Martin Carlin', :partner_email => 'martin#domain.co.uk')
#=> {:recipient_email=>"martin#domain.co.uk", :partner_name=>"Martin Carlin", :partner_email=>"martin#domain.co.uk"}
#=> 1
#=> 2
If you're trying to use named parameters instead you'd need to redefine your initialize as
def initialize(recipient_email:a,partner_name:b,partner_email:c)
and invoke it as below -
a = A.new(recipient_email:'martin#domain.co.uk', partner_name:'Martin Carlin', partner_email:'martin#domain.co.uk')

Related

Applying filters to Rails model

def show_category
category_selected = params[:genre]
all_movies = Movie.all
#movies_in_category = all_movies.where(:category => category_selected)
puts "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
puts category_selected
puts #movies_by_category.length
end
I have the above controller function which gets called with a parameter.
params[:genre]
the above line print out the parameter just fine.
all_movies = Movie.all
#movies_in_category = all_movies.where(:category => category_selected)
But the above 2 lines of code don't seem to be executed at all (I don't see the SQL queries for the above 2 lines being printed on the Rails console.
I also tried this but still couldn't see the SQL on the Rails console:
#movies_in_category = Movie.where(:category => category_selected)
What am I doing wrong here?

Remote API method won't create records based on received params

I have an api for mass creating records of a model Series. A remote machine sends a POST request to my url, with an array #series passed as a json parameter, like this:
#series = [{:id=>1,name:"test"}, {:id=>2,name:"test2"}]
req = Net::HTTP::Post.new(post_uri, 'Content-Type' => 'application/json')
req.body = {series: #series}.to_json
res = http.request(req)
but I cannot for the life of me get the respective Series to be created. Here is the method that receives the data and is supposed to create one Series for each hash in the #series array:
def api
series = params[:series]
series.each do |s|
name = s[:name]
if !Series.where(name: name).exists?
Series.create(s)
end
end
end
The params are definitely passed through, but no Series are created. When I check my logs there's a 500 error, but since it's remote, I have no way of getting a more specific error.
When I remove the params and just create a generic Series for each hash in the #series array, it works. For example, with the following code, if #series has 3 hashes, 3 Series are created:
def post_product_data
series = params[:series]
series.each do |s|
name = s[:name]
if !Series.where(name: name).exists?
Series.create #GENERIC SERIES NOT BASED ON PARAMS
end
end
end
I thought it might be a permissions issue, so I tried permitting all params. But when I changed the method to this, I got a "undefined method "permit!" error:
def post_product_data
series = params[:series]
series.each do |s|
name = s[:name]
if !Series.where(name: name).exists?
Series.create(s.permit!) #TRIED PERMITTING ALL PARAMS
end
end
end
Anyone have any ideas?
UPDATE
I changed the offending line to this:
Series.create({id: s[:id], name: s[:name]})
and now it works. I have no idea why, since the hashes should have been inserting the exact same thing. But at least it works finally.

Creating new class to put into an Array in Ruby

I am coming from a C# background and trying to learn Ruby and Ruby on Rails. I have the following Car class - note the build_xml method I need in order to build XML in that syntax and then pass to a WebService
class Car
##array = Array.new
#this will allow us to get list of all instances of cars created if needed
def self.all_instances
##array
end
def initialize(id, model_number, engine_size, no_doors)
# Instance variables
#id = id
#model_number = model_number
#engine_size = engine_size
#no_doors = no_doors
##array << self
end
def build_car_xml
car = { 'abc:Id'=> #id, 'abc:ModelNo' => #model_number, 'abc:ES' => #engine_size, 'abc:ND' => #no_doors}
cars = {'abc:Car' => [car] }
end
end
In another class then I was using this as below:
car1 = Car.new('1', 18, 3.0, 4)
request = car1.build_car_xml
This works as expected and the request is formatted how I need and the webservice returns the results. I now want to expand this however so I can pass in an array of cars and produce the request XML - however I am struggling to get this part working.
So far I have been trying the following (for now I am ok with just the Id changing as it is the only parameter required to be unique):
car_array = []
(1..10).each do |i|
car_array << Car.new(i.to_s, 18, 3.0, 4)
end
Am I correct in saying that I would need to define a new build_car_xml method on my Car class that can take an array of cars and then build the xml so my request call would be something like:
request = Car.build_car_xml(car_array)
What i am unsure of is 1) - is this the correct way of doing things in Ruby and 2) how to construct the method so that it is Building the XML in the correct format in the way it was when I call it on the single object - i.e - I need the namespaces added before the actual value.
def build_car_xml(car_array)
#here is where I am unsure how to contruct this method
end
Possible solution ('abc:Car' is a wrong name, should be Cars if you want it to hold an array):
class Car
...
def self.build_cars_xml(cars)
{ 'abc:Car' => cars.map(&:build_car_xml) }
end
def build_car_xml
{ 'abc:Id'=> #id, 'abc:ModelNo' => #model_number, 'abc:ES' => #engine_size, 'abc:ND' => #no_doors }
end
end
cars =
(1..10).map do |i|
Car.new(i.to_s, 18, 3.0, 4)
end
Car.build_cars_xml(cars)
It doesn't meet your requirements as instance build_car_xml doesn't generate Car namespace, but for me it's some inconsistency. Your XML is actually a collection, even if it has just one element, instance method should not be responsible for collection. Car.build_cars_xml([Car.new(...)] looks more logical to me.

How to pass Arguments and use those in (resque-status) Resque::JobWithStatus?

my resque worker class is:
require 'resque'
require 'resque/job_with_status'
class PatstatResqueWorker < Resque::JobWithStatus
#queue = :my_worker_q
def self.perform(query, label)
puts "query:"
puts options['query']
puts "label:"
puts options['label']
end
end
and my controller part, where I call this resque is...
class MyController < ApplicationController
def resque
job_id = PatstatResqueWorker.create(:query => #query, :label => "yes")
status = Resque::Plugins::Status::Hash.get(job_id)
end
end
and its not working :(
if i remove the parameter from resque function it says Wrong number of arguments (2 for 0) and if i add the parameter section back it says options not defined :(
Could you help?
The reason you're getting the "options not defined" error is that you haven't defined options in the method that uses it. Your self.perform method expects to receive two distinct arguments, query and label, but the code inside the method expects to have an options hash. You've got to choose one or the other.
Either do this:
def self.perform(query, label)
# use the parameters we've already defined
puts "query:"
puts query
puts "label:"
puts label
end
# call it like this
PatstatResqueWorker.create(#query, "yes")
Or else do this:
# change the method signature to match what you're doing
def self.perform(options)
puts "query:"
puts options['query']
puts "label:"
puts options['label']
end
# call it like this, with string keys
PatstatResqueWorker.create('query' => #query, 'label' => "yes")
Notice that with the hash version, I changed the call to use strings for the hash keys instead of symbols. You can use symbols if you want, but you'd have to change it in the body of the method as well (i.e. options[:query] instead of options['query']). You've just got to be consistent.

How to remove special characters from params hash?

I have one application with the following code:
quantity = 3
unit_types = ['MarineTrac','MotoTrac','MarineTrac']
airtime_plan = 'Monthly Airtime Plan'
url = "http://localhost:3000/home/create_units_from_paypal?quantity=#{quantity}&unit_types=#{unit_types}&airtime_plan=#{airtime_plan}"
begin
resp = Net::HTTP.get(URI.parse(URI.encode(url.strip)))
resp = JSON.parse(resp)
puts "resp is: #{resp}"
true
rescue => error
puts "Error: #{error}"
return nil
end
It sends data to my other application via the URL params query string. This is what the controller method of that other application looks like:
def create_units_from_paypal
quantity = params[:quantity]
unit_types = params[:unit_types]
airtime_plan = params[:airtime_plan]
quantity.times do |index|
Unit.create! unit_type_id: UnitType.find_by_name(unit_types[index]),
airtime_plan_id: AirtimePlan.find_by_name(airtime_plan),
activation_state: ACTIVATION_STATES[:activated]
end
respond_to do |format|
format.json { render :json => {:status => "success"}}
end
end
I get this error:
<h1>
NoMethodError
in HomeController#create_units_from_paypal
</h1>
<pre>undefined method `times' for "3":String</pre>
<p><code>Rails.root: /Users/johnmerlino/Documents/github/my_app</code></p>
I tried using both raw and html_safe on the params[:quantity] and other params, but still I get the error. Note I had to use URI.encode(url) because URI.parse(url) returned bad uri probably because of the array of unit_types.
Change:
quantity.times do |index|
To:
quantity.to_i.times do |index|
The reason you are having this problem is because you are treating the params values as the types that you originally tried to send, but they are actually always going to be strings. Converting back to the expected 'type' solves your problem.
However, you have some more fundamental problems. Firstly, you are trying to send an array by simply formatting it to a string. However, this is not the format that the receiving application expects to translate back to an array. Secondly, there is duplication in your request - you don't need to specify a quantity. The length of the array itself is the quantity. A better method would be to build your url like this:
url = 'http://localhost:3000/home/create_units_from_paypal?'
url << URI.escape("airtime_plan=#{airtime_plan}") << "&"
url << unit_types.map{|ut| URI.escape "unit_types[]=#{ut}" }.join('&')
On the receiving side, you can do this:
def create_units_from_paypal
unit_types = params[:unit_types]
airtime_plan = params[:airtime_plan]
quantity = unit_types.try(:length) || 0
#...

Resources