Error passing object to method using send() in Ruby - ruby-on-rails

I'm having a problem using send() to call a method while passing said method an object. I receive an undefined method ``employee_feedback(#<WorkItem:0x000000057cc7c0>)' for WorkItemMailer:Class error.
This is in my work_item.rb model:
def send_work_item_mail
forms_needing_mail = ["employee", "install", "repair"]
if forms_needing_mail.include?(self.form)
WorkItemMailer.send("#{self.form}_feedback(#{self})").deliver_now
end
end
Which is being called as:
#work_item.send_work_item_mail
in my work_items_controller.rb
And the following is the method in my mailer:
def employee_feedback(work_item)
#work_item = work_item
#employee = User.find_by(id: #work_item.employee)
#manager = User.find_by(id: #employee.manager)
mail to: #manager.email, subject: "Employee feedback for #{#employee.name}"
end
Am I using send incorrectly, or is there something else at play here?

try this
WorkItemMailer.send("#{self.form}_feedback".to_sym, self).deliver_now

Calling send on an object is identical as calling a method directly. The difference is that you pass the method name as an argument to send.
Subsequent arguments to send, (after the method name) are passed as parameters in the method
So this:
WorkItemMailer.employee_feedback(self)
Should be called as:
WorkItemMailer.send(:employee_feedback, self)
In your case:
WorkItemMailer.send("#{self.form}_feedback", self).deliver_now

Related

How do I extract one parameter from multiple request parameters using Rails?

If I want to get out one parameter from request parameters below, how do I do so?
{"utf8"=>"✓", "authenticity_token"=>"***", "users_unsubscribe_mail_magazine_form"=>{"email"=>"tea#tea.com", "dm"=>"1"}, "commit"=>"Send Mail", "controller"=>"users/unsubscribe_mail_magazines", "action"=>"create"}
I want to get "users_unsubscribe_mail_magazine_form"=>{"dm"=>"1"}, and pass the parameter to another page.
When I type into the live shell
params[:users_unsubscribe_mail_magazine_form][:dm]
I get an error message
"!! #<NameError: undefined local variable or method `params' for #UnsubscribeMailMagazineMailer:0x00007f14c86c5848>"
Thank you.
PS:
I am using form_for "f.submit" to send the parameters.
PPS:
This is how I call my mailer.
def create
#unsubscribe_form = Users::UnsubscribeMailMagazineForm.new mail_magazine_unsubscribe_params
#dm = #unsubscribe_form.dm
if #unsubscribe_form.valid?
user = User.find_by(email: #unsubscribe_form.email)
UnsubscribeMailMagazineMailer.unsubscribe(user).deliver_now unless user.nil?
redirect_to action: :create_complete
else
render action: :new
end
end
The params are only available in the controller. When you want to use the parameters or single values from them in a mailer then you have to pass that value to the mailer in the arguments.
Something like this should work:
# in the controller
UnsubscribeMailMagazineMailer.unsubscribe(
user, params[:users_unsubscribe_mail_magazine_form][:dm]
).deliver_now if user
# in your mailer
def unsubscribe(user, dm)
# have the `user` and the `dm` value available in local variables
end

Using Twilio API in Ruby, How to pass parameters between actions?

In the ruby controller, I have two methods in the same controller.
class NotificationsController < ApplicationController
def send
my_variable = xxx
twilio_client = Twilio::REST::Client.new account_sid, auth_token
twilio_client.send_text(user, message)
end
def receive
response = Twilio::TwiML::MessagingResponse.new
response.message do |message|
message.body("Hello World!")
end
puts params["Body"]
end
end
The method send would send message to the specific user, and the method receive receive the message from the user. However, the my_variable in the send method lost between actions. I want to use the variable in the receive method, but don't know how to do that.
I tried to assign the variable one to a session hash. session[:variable_one] = variable_one, and access it in the method receive. But it turns out the session[:variable_one] in the method receive is nil.
I read the documents from Twilio, but still very confuse how to pass the extra parameters.
Could you please have some suggestions on this problem? Thanks so much.

Accessing more than default parameters (to, from, subject, reply_to) for rails mail interceptor

I have a method within a mailer called notification_mailer.rb:
def reminder_email
#community = #reminder.community
subject = "random subject text"
mail(from: address_for(support), reply_to: address_for(support), to: to_address, subject: subject)
end
I am trying to use a mail interceptor check_mail_settings.rb:
class CheckMailSettings
def self.delivering_email(mail)
if #community.status = "mute"
mail.perform_deliveries = false
end
end
end
ActionMailer::Base.register_interceptor(CheckMailSettings)
But this interceptor does not actually have access to the #community variable. I have tried passing it in the mail call in notification_mailer.rb like so
mail(community: #community, from: address_for(support).....)
and accessing it within the interceptor check_mail_settings.rb like this
mail.community
but that does not work either.
Is there any way I can get access to this #community variable within the interceptor check_mail_settings.rb or will I need to do any conditionals involving #community within the notification_mailer.rb beforehand?
while i don't think that what you are doing there really makes sense, it is possible.
in the interceptor you get an instance of Mail::Message. it has access to whatever you pass into the mail call.
so in the example you provided it would be
mail[:community].value

Rails testing controller private method with params

I have a private method in a controller
private
def body_builder
review_queue = ReviewQueueApplication.where(id: params[:review_queue_id]).first
...
...
end
I would like to test just the body_builder method, it is a method buidling the payload for an rest client api call. It needs access to the params however.
describe ReviewQueueApplicationsController, type: :controller do
describe "when calling the post_review action" do
it "should have the correct payload setup" do
#review_queue_application = ReviewQueueApplication.create!(application_id: 1)
params = ActionController::Parameters.new({ review_queue_id: #review_queue_application.id })
expect(controller.send(:body_builder)).to eq(nil)
end
end
end
If I run the above it will send the body_builder method but then it will break because the params have not been set up correctly as they would be in a call to the action.
I could always create a conditional parameter for the body_builder method so that it either takes an argument or it will use the params like this def body_builder(review_queue_id = params[:review_queue_id]) and then in the test controller.send(:body_builder, params), but I feel that changing the code to make the test pass is wrong it should just test it as it is.
How can I get params into the controller before I send the private method to it?
I think you should be able to replace
params = ActionController::Parameters.new({ review_queue_id: #review_queue_application.id })
with
controller.params = ActionController::Parameters.new({ review_queue_id: #review_queue_application.id })
and you should be good. The params is just an attribute of the controller (the actual attribute is #_params but there are methods for accessing that ivar. Try putting controller.inspect in a view).

How to transform a string into a variable/field?

I'm new to Ruby and I would like to find out what the best way of doing things is.
Assume the following scenario:
I have a text field where the user can input strings. Based on what the user inputs (after validation) I would like to access different fields of an instance variable.
Example: #zoo is an instance variable. The user inputs "monkey" and I would like to access #zoo.monkey. How can I do that in Ruby?
One idea that crossed my mind is to have a hash:
zoo_hash = { "monkey" => #zoo.monkey, ... }
but I was wondering if there is a better way to do this?
Thanks!
#zoo.attributes gives you a hash of the object attributes. So you can access them like
#zoo.attributes['monkey']
This will give nil if the attribute is not present. Calling a method which doesn't exist will throw NoMethodError
In your controller you could use the public_send (or even send) method like this:
def your_action
#zoo.public_send(params[:your_field])
end
Obviously this is no good, since someone can post somehing like delete_all as the method name, so you must sanitize the value you get from the form. As a simple example:
ALLOWED_METHODS = [:monkey, :tiger]
def your_action
raise unless ALLOWED_METHODS.include?(params[:your_field])
#zoo.public_send(params[:your_field])
end
There is much better way to do this - you should use Object#send or (even better, because it raises error if you try to call private or protected method) Object#public_send, like this:
message = 'monkey'
#zoo.public_send( message )
You could implement method_missing in your class and have it interrogate #zoo for a matching method. Documentation: http://ruby-doc.org/core-1.9.3/BasicObject.html#method-i-method_missing
require 'ostruct' # only necessary for my example
class ZooKeeper
def initialize
#zoo = OpenStruct.new(monkey: 'chimp')
end
def method_missing(method, *args)
if #zoo.respond_to?(method)
return #zoo.send(method)
else
super
end
end
end
keeper = ZooKeeper.new
keeper.monkey #=> "chimp"
keeper.lion #=> NoMethodError: undefined method `lion'

Resources