Check request parameter - ruby-on-rails

I want to check request header parameters. If an attribute is missing , I don't accept the request.
Current implementation is here:
class SampleController < ApplicationController
before_action :render_message, unless: :check_header
// GET method
def index
....
end
def check_header
return request.headers["key1"] && request.headers["key2"] && request.headers["key3"]
end
def render_message
render json: { message: "missing the custom attribute in the header" }, status:400
end
How can I beautify this code?

I would probably rewrite the method to something like this:
def check_header
required_headers = %w[key2 key2 key3]
required_headers.all? { |key| request.headers[key] }
end
Note that the above version has the same behavior then your example. If you really need to check that the values are present (an empty string is still true-ish) then you will need to check present? too.
def check_header
required_headers = %w[key2 key2 key3]
required_headers.all? { |key| request.headers[key].present? }
end
And I would think about using a constant instead of the local variable required_headers.

Related

Trigger rails controller function - Paypal Website Standard IPN

I've got a Paypal IPN that comes into a PaymentNotificationsController in my app. However, some variables depend on the number of items in a cart, so i want to extract them before creating the PaymentNotification.
So far, i've got:
class PaymentNotificationsController < ApplicationController
protect_from_forgery except: [:create]
def create
PaymentNotification.create!(params: params,
item_number: params[:item_number], item_name: params[:item_name], quantity: params[:quantity]
render nothing: true
end
end
However, when the notification comes from PayPal, it comes in the form of item_name1, item_number1, quantity1, item_name2, item_number2, quantity2 and so on.
Even if its just one item, it would come as item_name1, item_number1, quantity1, option1 and so on.
I have this function to try and extract the variables, but i don't know how to trigger the function. I tried using a before_action at the top of the controller but it didn't work. Returned wrong number of arguments(0 for 1):
ITEM_PARAM_PREFIXES = ["item_name", "item_number", "quantity"]
def extract_ipn_items_params(params)
item_params = []
loop do
item_num_to_test = item_params.length + 1
item_num_suffix = item_num_to_test.to_s
possible_param_name = ITEM_PARAM_PREFIXES[0] + item_num_suffix
if params.include?(possible_param_name)
this_item_params = {}
ITEM_PARAM_PREFIXES.each do |prefix|
this_item_params[prefix] = params[prefix + item_num_suffix]
end
item_params.push this_item_params
else
return item_params
end
end
end
So i'm asking, how do i trigger the function to extract the variables and put them into params[:item_number], params[:item_name], params[:quantity] for each item in the cart so if there are two items, two separate PaymentNotifications would be created?
Note: Both methods are in the same PaymentNotificationsController.
Any help would be appreciated. Thanks in advance!
I assume your method extract_ipn_items_params already fetches the data you require, you can remove the params argument to the method, as the params is always available in the actions/methods of the controller.
ITEM_PARAM_PREFIXES = ["item_name", "item_number", "quantity"]
def extract_ipn_items_params
mod_params = Hash.new{|k, v| k[v] = {} }
ITEM_PARAM_PREFIXES.each do |item_data_key|
key_tracker = 1
loop do
current_key = (item_data_key + key_tracker.to_s).to_sym
if params.include? current_key
mod_params[key_tracker][item_data_key] = params[current_key]
else
break
end
key_tracker += 1
end
end
mod_params
end
The method returns a hash of hashes like:
{1 => {item_name: 'Item 1', item_number: 1084, quantity: 15}}, if you have nested attributes set up for a user, I think you should be able to do something like, not really sure, but should be possible:
user.update(payment_notifications_attributes: extract_ipn_items_params)
Let me know if that works for you.
UPDATE
Based on the Github Gist, here's something I was able to come up with:
class PaymentNotificationsController < ApplicationController
protect_from_forgery except: [:create]
ITEM_PARAM_PREFIXES = ["item_name", "item_number", "quantity", "option_name"]
def create
extract_ipn_items_params.each do |key, values|
# this approach loops through all the returned results, nested attributes may help abstract this though
PaymentNotification.create(values)
render nothing: true
end
def details
# params.extract_ipn_items_params #this doesn't exist as params is an instance of ActionController::Parameters
PaymentNotification.update_attributes(line_item_id: params[:item_number], product_title: params[:item_name], option_name: params[:option_name], quantity: params[:quantity])
end
private
def additional_attributes
# create this for additional merge attributes. A better place for these would be the parent of this
{
params: params,
cart_id: params[:invoice],
status: params[:payment_status],
transaction_id: params[:txn_id],
first_name: params[:first_name],
last_name: params[:last_name],
email: params[:payer_email],
address_name: params[:address_name],
address_street: params[:address_street],
address_city: params[:address_city],
address_state: params[:address_state],
address_zip: params[:address_zip],
address_country: params[:address_country]
}
end
def extract_ipn_items_params
mod_params = Hash.new{|k, v| k[v] = {}.merge(additional_attributes) }
ITEM_PARAM_PREFIXES.each do |item_data_key|
key_tracker = 1
loop do
current_key = (item_data_key + key_tracker.to_s).to_sym
if params.include? current_key
mod_params[key_tracker][item_data_key] = params[current_key]
else
break
end
key_tracker += 1
end
end
mod_params
end
end
Let me know if that fixes your problem.
You should have payment_id so you can find it by using gem 'paypal-sdk-rest'
payment = PayPal::SDK::REST::Payment.find payment_id
then you could see all details in payment object

ruby on rails accessing custom class attributes from its object

I have a custom class in my application controller. Like below:
class Defaults
def initialize
#value_1 = "1234"
#value_2 = nil
#data = Data.new
end
end
class Data
def initialize
#data_1 = nil
end
end
Now in my controller method i have created an object of type Defaults
def updateDefaultValues
defaults = Defaults.new
# i am unable to update the value, it says undefined method
defaults.value_2 = Table.maximum("price")
defaults.data.data_1 = defaults.value_2 * 0.3
end
How to access value_2 from defaults object?
defaults.value_2
Also, how to access data_1 attribute from data object within defaults object?
defaults.data.data_1
You should use attr_accessor:
class Defaults
attr_accessor :value_1, :value_2, :data
# ...
end
defaults = Defaults.new
defaults.value_1 = 1
# => 1
defaults.value_1
# => 1
As you are using def as a keyword to define the method, that means def is a reserved keyword. You can't use reserved keywords as a variable.
You just need to rename your variable name from def to something_else and it should work! Your code will look like this:
def updateDefaultValues
obj = Defaults.new
obj.value_2 = Table.maximum("price")
obj.data.data_1
end
EDIT:
As per OP's comment & updated question, he had used def just as an example, here is the updated answer:
You may need attr_accessor to make attrs accessible:
class Defaults
attr_accessor :value_1, :value_2, :data
...
...
end
class Data
attr_accessor :data_1
...
...
end
Add value_2 method in Defaults class
class Defaults
def initialize
#value_1 = "1234"
#value_2 = nil
#data = Data.new
end
def value_2
#value_2
end
end
class Data
def initialize
#data_1 = nil
end
end

How to mimic asp.net get set in rails

I am trying to mimic asp.net get{} set{} in rails, here is what i tried in my controller:
def get_segment=(segment)
if params[:s] != nil
segment = params[:s]
else
segment = "personal"
end
end
Then i am trying to access it like this:
#something = get_segment
But it always returns as nil.
How can i do this?
Thanks
Why are you using get segment=(segment)?
look like what you are wanting to do is test params[:s], so the = is uncessary, as is the segment parameter.
def get_segment
if params[:s] != nil
params[:s]
else
"personal"
end
end
I think this would give you what you want.
If you just want to mimic get{} set{} in C#, the property Segment
private string _segment;
public string Segment {
get { return _segment; }
set { _segment = value; }
}
is written as followed in Ruby:
# get
def segment
#segment
end
# set
def segment=(value)
#segment = value
end
# if you don't have additional logic, you can just write
attr_accessor :segment
Then you can use some_instance.segment to retrieve the value and some_instance.segment = some_value to modify the value.
According to your code sample above, you want to fetch s parameter with a default value if it doesn't exist. You should define a getter, not in the setter form as you have provided.
def get_segment # or just "segment"
params[:s] || "personal"
end

Saving URL params in a session (rails)

I'm trying to save the url params from ever page, into a session, so if someone fills out a form after navigating away from their landing page it keeps the campaign id. I've managed to make it work page by page, so if they land on the form with params it keeps it, but if they navigate away obviously it doesn't. I currently have:
Controller:
def campaign
if params[:campaign]!= nil
session[:campaign] = params[:campaign]
end
end
def post
rif = Registerinterest.find(:all, :conditions => ["reference = ?", session[:campaign]])
if rif.count == 0
post["Campaign_ID"] = "701D00000001111"
else
post["Campaign_ID"] = rif.first.campaign_id
end
end
It worked when i used params, but not session, so i'm assuming i'm not saving it properly?
You could add a before filter in controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter persist_campaign_session
def persist_campaign_session
session[:campaign] ||= params[:campaign]
end
end
If session[:campaign] is set it will be used, otherwise params[:campaign]will be used. You should implement
the reset of session[:campaign] at a good place.
I put this in my application layout:
- if params[:campaign] != nil || params[:campaign] != ""
- session[:campaign] == params[:campaign]
and then that made the controller work properly:
def post
rif = Registerinterest.find(:all, :conditions => ["reference = ?", session[:campaign]])
if rif.count == 0
post["Campaign_ID"] = "701D00000001111"
else
post["Campaign_ID"] = rif.first.campaign_id
end
end

How do I assign a value from params, or session, whichever exists?

What is the "Rails-way" or the "Ruby-way" of doing the following:
In my controller, I'm creating and instance of an Options class. It will be initialized with information in the params hash if the params hash exists. Otherwise, it will check the sessions hash for the information. Finally, it will initialize with defaults if neither params nor session has the data it needs. Here is how I'm doing it now (it works fine, but it seems a little ugly):
if params[:cust_options]
#options = CustomOptions.new( params[:cust_options] )
else
if session[:cust_options
#options = CustomOptions.new( session[:cust_options] )
else
#options = CustomOptions.new
end
end
session[:cust_options] = #options.to_hash
Like I said, everything is working fine, I'm just looking for a more idiomatically Ruby way of writing this block of code.
Update
This is what my code looks like now (thanks henning-koch and jdeseno):
#options = CustomOptions.new( params[:cust_options] || session[:cust_options] || {} )
If I leave the final condition (|| {}) off that line of code, what happens in my initialize method when neither params[:cust_options] nor session[:cust_options] are defined, or both are nil?
My initialize definition looks like this:
def initialize( options = {} )
# stuff happens ...
end
A shorter way to write this would be
#options = CustomOptions.new(params[:cust_options] || session[:cust_options])
Good luck.
You can use the 'or' operator to default:
#options = CustomOptions.new( session[:cust_options] || params[:cust_options] || {} )
You can try to put these codes in the controller that you have. Doing this will make the session key available for all the actions in the controller. It is also guaranteed that before any of the controller's action is called, the session value has been set.
# Place this under the controller class definition
before_filter :set_session_value
private
def set_session_value
session[:cust_options] = find_cust_options_value
end
def find_cust_options_value
return CustomOptions.new(params[:cust_options]) if params[:cust_options]
return CustomOptions.new(session[:cust_options]) if session[:cust_options]
return CustomOptions.new
end

Resources