dynamically generate an attribute on an object, ruby, rails - ruby-on-rails

Given these params:
ex: 1
{:field => 'admin', :id => "1"}
ex: 2
{:field => 'client', :id => "1"}
ex: 3
{:field => 'partner', :id => "1"}
Is it possible, (and how of course) could i dynamically apply this to the User model such as:
controller
#note the field attribute is not a field
#the field attribute I'm trying to set above to what are given in the params hash
def update_user
field = params[:field]
#user = User.find(params[:id])
#user.field = !#user.field
#user.save(false)
render :nothing => true
end
fyi
Why not just send a has with params and update the with update_attributes(params[:user])? Because the users attributes are protected and it's just easier to update a boolean this way.

I would do something like this:
#user = User.where("#{params[:field]} = ?", params[:id]).first if ["admin", "client", "partner"].include?(params[:field])
(The "include?" is a security check to prevent users from choosing some other field you don't want them to)

Related

undefined method `each' for "#<Complaigns::ActiveRecord_Relation:0x00000003cfb4c8>":String

I have a model, called Complaign, with some other attributes along with the date of complaign (c_date).
In the ComplaignController, I have an index view, which displays all the complaigns. There is a filter which takes from date and to date. On filtering that, it works fine, and properly displays the complaigns fired on those dates.
Now I want the result of this query to be passed on to a different method, say export method.
I thought of passing this from the index view, since it is stored in #complaigns.
This is my index method:
def index
if params[:from] && params[:to]
from = params[:from].to_date
to = params[:to].to_date
#complaigns = Complaigns.where(:c_date => from..to)
else
#complaigns = Complaigns.all
end
end
In the index view, this is what I have written
<%= link_to "Export", {:controller => "complaigns", :action => "export", :complaigns => #complaigns}%>
This is the export method
def export
#complaigns = params[:complaigns]
end
Now, in the export view, when I do the follwing line:
#complaigns.each, I get this error--
undefined method `each' for "#<Complaign::ActiveRecord_Relation:0x00000003cfb4c8>":String
Now this is because, I think, there is no method each in String class. Is there any way, I can convert the String to Complaign type in the method export or while passing it from the index view, pass it as Complaign object instead of String? Is there any other way of doing this?
You can't pass Ruby on Rails model objects directly in the controller parameters, you can pass their corresponding ids and then load the models from the database. HTTP / Ruby on Rails is stateless. If you always go to index before export, one way how to solve this might be:
<%= link_to "Export", {:controller => "complaigns", :action => "export", :complaigns => #complaigns.map(&:id)}%>
def export
#complaigns = Complaigns.find(params[:complaigns])
end
It looks like #complaigs is passed as string instead of actual active_record relations object. You should calculate #camplaigs in export instead of sending them. Or you can pass array of ids
#complaigns.collect(&:id)
HTTP is stateless protocol, which means each request is independent from the other (unless you use cookie or session). For your export method, it knows nothing about the result of index method unless you pass enough information to it. So a simple solution can be:
index view
<%= link_to "Export", {:controller => "complaigns", :action => "export", :from => params[:from], :to => params[:to] }%>
export method
def export
if params[:from] && params[:to]
from = params[:from].to_date
to = params[:to].to_date
#complaigns = Complaigns.where(:c_date => from..to)
else
#complaigns = Complaigns.all
end
end
Here, the parameters for index is passed to export.
But this method is not DRY enough. You can consider using index for export like this:
def index
if params[:from] && params[:to]
from = params[:from].to_date
to = params[:to].to_date
#complaigns = Complaigns.where(:c_date => from..to)
else
#complaigns = Complaigns.all
end
if params[:export].present?
render 'export'
else
render 'index'
end
end
Then in your export link, you can use this:
<%= link_to "Export", {:controller => "complaigns", :action => "index", :from => params[:from], :to => params[:to], :export => true }%>
PS. These codes are not tested. Just for demonstration purpose.
You can't do what you are trying to do. The problem is that when the view is rendered, the resulting HTML is text, and therefore #complaigns is turned into it's equivalent text (the same as #complaigns.to_s).
To do what you want, you need to pass to your link, the same paramaters you used to create #camplaigns in your index view. So:
Change your link to:
<%= link_to "Export", {:controller => "complaigns", :action => "export", :to => params[:to], :from => params[:from]}%>
And then change your export method to:
def export
index
end

Showing item price, item id, item name in paypal payment screen

I have used gem "active_paypal_adaptive_payment" also set the payment options
def checkout
recipients = [recipientarray]
response = gateway.setup_purchase(
:return_url => url_for(:action => 'action', :only_path => false),
:cancel_url => url_for(:action => 'action', :only_path => false),
:ipn_notification_url => url_for(:action => 'notify_action', :only_path => false),
:receiver_list => recipients
)
# For redirecting the customer to the actual paypal site to finish the payment.
redirect_to (gateway.redirect_url_for(response["payKey"]))
end
It is redirecting to the paypal payment page..
This is the page
In payment summary it does not displaying any item name , price, etc..
can any one suggest how to configure it . Please help
Thanks
You may want to try using the "ActiveMerchant" gem instead - it's updated by Shofify and we've got it to do exactly what you're looking for.
Problem
The way to get PayPal to list the items is to use the ExpressCheckout version (I think you're just setting up a peer-to-peer payment), and then pass the items in a hash array. We use a cart, but you may have something else.
The trick with paypal epxress is that you have to get all the totals to add up properly. As you will see in the code I post, we are just using a static shipping value for now (we're still developing this current project), but you can omit shipping if you don't need it.
Solution
I can only vouch for ActiveMerchant, because that's the only code I've got, but here is what we do:
Routes
#config/routes.rb
get 'checkout/paypal' => 'orders#paypal_express', :as => 'checkout'
get 'checkout/paypal/go' => 'orders#create_payment', :as => 'go_paypal'
Orders Controller
#controllers/orders_controller.rb
class OrdersController < ApplicationController
#Paypal Express
def paypal_express
response = EXPRESS_GATEWAY.setup_purchase(total,
:items => cart_session.build_order, #this is where you create the hash of items
:subtotal => subtotal,
:shipping => 50,
:handling => 0,
:tax => 0,
:return_url => url_for(:action => 'create_payment'),
:cancel_return_url => url_for(:controller => 'cart', :action => 'index')
)
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end
#some other stuff is here....
end
Build Items
#models/cart_session.rb (we use this with a cart)
#Build Hash For ActiveMerchant
def build_order
#Take cart objects & add them to items hash
products = cart_contents
#order = []
products.each do |product|
#order << {name: product[0].name, quantity: product[1]["qty"], amount: (product[0].price * 100).to_i }
end
return #order
end
end

Why isn't Rails recognizing nil if blank in my form?

I'm reworking a Rails 2 website. Right now, I'm getting an error, and I think it's because a value is being submitted as blank instead of .nil. However, my attempts to keep it nil don't seem to be working. I appreciate any help you have to offer.
From Model, based on Make blank params[] nil
NULL_ATTRS = %w( start_masterlocation_id )
before_save :nil_if_blank
protected
def nil_if_blank
NULL_ATTRS.each { |attr| self[attr] = nil if self[attr].blank? }
end
View
I've got jQuery that adds a value to this hidden field when a start_masterlocation_id exists. I've also got jQuery that removes the field attribute when it does not exist.
<%= hidden_field :newsavedmap, :start_masterlocation_id, :id => "start-masterlocation-id-field" %>
Finally, here is the part of the controller that is throwing the error. This is the controller for the page that holds the form (Maptry), not the controller for Newsavedmap. I think I have to delete the #newsavedmap.id, #newsavedmap.mapname, and #newsavedmap.optimize lines now that I'm going with form handlers, but I don't think that's related to this error.
Controller
def maptry
#itinerary = Itinerary.find(params[:id])
if #itinerary.user_id == current_user.id
respond_to do |format|
#masterlocation = Masterlocation.find(:all)
format.html do
end
format.xml { render :xml => #masterlocation }
format.js do
#masterlocation = Masterlocation.find(:all)
render :json => #masterlocation.to_json(:only => [:id, :nickname, :latitude, :longitude])
end
end
if params[:newsavedmap_id]
#newsavedmap = Newsavedmap.find(:first, :conditions => {:id => params[:newsavedmap_id]})
#waypoint = Waypoint.find(:all, :conditions => {:newsavedmap_id => params[:newsavedmap_id]})
#newsavedmap.id = params[:newsavedmap_id]
#newsavedmap.mapname = Newsavedmap.find(:first, :conditions => {:id => params[:newsavedmap_id]}).mapname
#newsavedmap.optimize = Newsavedmap.find(:first, :conditions => {:id => params[:newsavedmap_id]}).optimize
if !#newsavedmap.start_masterlocation_id.nil?
#start_name = Masterlocation.find(:first, :conditions => {:id => #newsavedmap.start_masterlocation_id}).name
end
if !#newsavedmap.end_masterlocation_id.nil?
#end_name = Masterlocation.find(:first, :conditions => {:id => #newsavedmap.end_masterlocation_id}).name
end
else
#newsavedmap = Newsavedmap.new
end
else
redirect_to '/'
end
end
Error
This does not occur when a start_masterlocation_id is present in the database.
undefined method `name' for nil:NilClass
I solved this by ignoring the nil problem. Instead, I used
!#newsavedmap.start_masterlocation_id.blank?
This evaluates whether the data in the record is blank and then either does or doesn't do something. Obviously, this results in unwanted "blank" data being left inside my database, so it's not ideal, but it helped me move forward with the project. I'd appreciate any responses that deal directly with the nil issue and tell me how to have Rails ignore blank data in a form.

Shortening up respond_with( :include => xxx)

I'm looking for a way to shorten up the :include => :child inside a respond_with which generates json.
Here is an example, not sure if it is even possible, but I would like to find out.
In the controller:
#p = Parent.where('id = ?', params[:id])
respond_with(#p, :include => {:child1 => {}, :child2 => {}, :child3 => {:include => :grandchild1}})
Is there someway to include these all when I define the instance?
Maybe something like:
#p = Parent.includes(:child1, :child2, :child3, :grandchild1).where('id = ?', params[:id])
respond_with(#p)
Basically, I'm trying to DRY up my code ... I don't want to have to keep typing the include hash over and over ... Is there someway to just include all child objects in one call?
ActiveRecord has an as_json method that defines how the object should be outputted as json. You can ovveride this method to include the associated children by default so something like this:
class Parent < ActiveRecord::Base
# We went to display grandchildren by default in the output JSON
def as_json(options={})
super(options.merge(:include => {:child1 => {}, :child2 => {}, :child3 => {:include => :grandchild1}})
end
end
That should let you clean up your controller a bit, you only need this:
#parent = Parent.find(params[:id])
respond_with #parent

How can I get form_for to autopopulate fields based upon a non-model hash?

I'm building a multi-step form in rails. It's not javascript driven, so each page has its own controller action like "step1" "step2" etc. I know how to do multi-step wizards through JQuery but I don't know how to keep rails validations per page without getting into javascript, hence this way.
Anyways, my model is a User object but I'm storing all my variables in an arbitrary Newuser variable and using the following in the view:
<% form_for :newuser, :url => { :action => "step3" } do |u| %>
In the controller, I merge the current page's info with the overall hash using:
session[:newuser].merge!(params[:newuser])
This works great except that if the user clicks back to a previous page, the fields are no longer populated. How do I keep them populated? Do I need to change the object in the form_for to somehow refer to the session[:newuser] hash?
EDIT:
I guess I'm looking for more info on how form_for autopopulates fields within the form. If it's not built around a model but an arbitrary hash (in this case, session[:newuser]), how do I get it to autopopulate?
This is how we did a multi-step form with validations
class User < ActiveRecord::Base
attr_writer :setup_step
with options :if => :is_step_one? do |o|
o.validates_presence_of :name
end
with options :if => :is_step_two? do |o|
o.validates_presence_of :email
end
def setup_step
#setup_step || 1
end
def is_step_one?
setup_step == 1
end
def is_step_two?
setup_step == 2
end
def last_step?
is_step_two? #change this to what your last step is
end
end
Then in the controller:
UsersController
SETUP_STEPS{1 => 'new', 2 => 'step_two'}
def new
#user = User.new
end
def step_two
end
def create
#user = User.new(params[:user])
if !#user.valid?
render :action => SETUP_STEPS[#user.setup_step]
elsif #user.last_step?
#user.save
#do stuff
else
render :action => SETUP_STEPS[#user.setup_step]
end
end
end
And then in your forms, they are like like any other rails form with one exception, you will need a hidden field to hold the values from your previous steps.
- form_for #user, :url => users_path do |f|
- [:login, :password].each do field
= f.hidden_field field
What about still using a class for your population?
class User
attr_accessor :credit_card, :name, :likes_fried_chicken
def initialize(options = {})
options.each do |key, value|
self.send("#{key}=", value)
end
end
end
you could use some tableless model functions here if you wanted to include some validations.
Then in your controller steps:
def step_one
#user = User.new(session[:new_user])
end
your forms should continue to work.
Another option is just to set the value of the form objects directly from your session hash
- form_for :user, :url => step_2_path do |f|
= f.text_field :name, :value => session[:new_user][:name]

Resources