undefined method paypal_url in Rails - ruby-on-rails

I have a piece of code in Rails,
def create
#registration = Registration.new(registration_params)
if #registration.save
redirect_to #registration.paypal_url(registration_path(#registration))
else
render :new
end
end
I took it from tutorial. But I need just in this line:
#registration.paypal_url(registration_path(#registration))
Now, about my own controller, feed_controller, where
def create
#feed = Feed.new(check_params)
end
In the view erb file I put:
#feed.paypal_url(feed_path(#feed))
In my feed.rb (model):
def paypal_url(return_path)
values = {
business: "merchant#gotealeaf.com",
cmd: "_xclick",
upload: 1,
return: "#{Rails.application.secrets.app_host}#{return_path}",
invoice: id,
amount: course.price,
item_name: course.name,
item_number: course.id,
quantity: '1'
}
"#{Rails.application.secrets.paypal_host}/cgi-bin/webscr?" + values.to_query
end
Rake routes:
feed GET /:locale/feed(.:format) feed#index
feed#create POST /:locale/feed/create(.:format)
feed#new feed_new GET /:locale/feed/new(.:format)
feed#destroy feed_destroy GET /:locale/feed/destroy(.:format)
feed#edit feed_edit GET /:locale/feed/edit(.:format)
feed#update feed_update GET /:locale/feed/update(.:format)
But it prints the next error:
undefined method `paypal_url' for <#Feed::ActiveRecord_Relation:0x007fee24f5fc98>
How can I fix it? What is the problem?
UPDATE
def index
#current_user_is = current_user.email
session[:email] = #current_user_is
session[:id] = current_user.id
unless (current_user.member.present?)
#member = Member.new(:user_id => current_user.id)
#member.save()
redirect_to '/feed'
else
#new_feed = Feed.new
#feed = Feed.where(:member_id => current_user.member.id)
#category = Category.all
render 'home/uploads'
end
end

Simply use def self.paypal_url(return_path) instead of def paypal_url(return_path).
Explanation
You ran into your problem by defining a Class Method instead of an Instance Method, there's other posts discussing this.
The basic difference is, when defining:
def self.get_some_url
# code to return url of an instance
end
you can easily get the desired url of any objects, as in a view:
<% #feeds.each do |feed| %>
<%= feeds.get_some_url %>
<% end %>
Now calling Feed.get_some_url on the class would make no sense. Which url of the thousands would it call?
But there is a lot of use for class methods (where you define the method without self as you did)
def get_top_5
# code to return the top 5 most viewed feeds
end
Since this has nothing to do with a single instance, you define it for the entire Class. Leading to this call: Feed.get_top_5, which makes perfectly sense.
The second problem was not understanding the difference between where & find, this post will help you out with that.

Related

session method cannot be called 2 times in controller

In the code below, when the #call method executes, it redirects the call to the #connect method to play an audio, then the #connect method redirects to #menu_selection where everything breaks. the error I get in heroku logs is that sessions is nil or defined.
What I dont understand is that I am already using session[:user_id] in the first method #call. why is it no defined in the #menu_selection method?
def call
#list = User.find_by(id: session[:user_id]).contact_lists.find_by(id: session[:last_contact_list_id])
#contacts = #list.contacts
#client = Twilio::REST::Client.new(##account_sid, ##auth_token)
#contacts.each do |contact|
#call = #client.account.calls.create(
:from => '+18056234397', # From your Twilio number
:to => '+1' + contact.phone , # To any number
:url => root_url + "connect"
)
end
redirect_to root_path
end
def connect
response = Twilio::TwiML::Response.new do |r|
r.Play 'https://clyp.it/l1qz52x5.mp3'
r.Gather numDigits: '1', action: menu_path do |g|
g.Play 'https://a.clyp.it/2mue3ocn.mp3'
end
end
render :xml => response.to_xml
end
def menu_selection
list = User.find_by(id: session[:user_id]).contact_lists.find_by(id: session[:last_contact_list_id])
user_selection = params[:Digits]
#client = Twilio::REST::Client.new(##account_sid, ##auth_token)
case user_selection
when "1"
#output = "say something."
twiml_say(#output, true)
when "2"
twiml_dial("+1805XXXXX")
when "3"
#output = "Bye Bye..."
twiml_say(#output, true)
end
end
In the #menu_selection method I get the error : undefined local variable or method `session'
Its in the first line where I'm defining the "list" variable.
I never had this kind of issue before. If anyone knows whats going on, I would appreciate your help.
I tried defining the first #list variable as a class variable outside of the method #call but It gives me the same error that I get now. I also tried making it a class variable inside the #call method to try using it in #menu_selection method, but I get an "##list is undefined" error.
Twilio developer evangelist here.
The problem here is that the session in the #call action is between your user and the server. However, when you initiate a call and Twilio calls back to your server the session between Twilio and the server is completely different.
In this situation, you need to pass the data you need Twilio to know through your URL. So, instead of just sending the connect URL, send it with the parameters you need later. So your #call action would look like:
def call
#list = User.find_by(id: session[:user_id]).contact_lists.find_by(id: session[:last_contact_list_id])
#contacts = #list.contacts
#client = Twilio::REST::Client.new(##account_sid, ##auth_token)
#contacts.each do |contact|
#call = #client.account.calls.create(
:from => '+18056234397', # From your Twilio number
:to => '+1' + contact.phone , # To any number
:url => root_url + "connect?user_id=#{session[:user_id]}&last_contact_list_id=#{session[:last_contact_list_id]}"
)
end
redirect_to root_path
end
Then, your #connect action will need to pass those on to your #menu_selection action too (note the menu_path line):
def connect
response = Twilio::TwiML::Response.new do |r|
r.Play 'https://clyp.it/l1qz52x5.mp3'
r.Gather numDigits: '1', action: menu_path(:user_id => params[:user_id], :last_contact_list_id => params[:last_contact_list_id] do |g|
g.Play 'https://a.clyp.it/2mue3ocn.mp3'
end
end
render :xml => response.to_xml
end
Finally, you will be able to use those parameters, instead of the session, in your #menu_selection action:
def menu_selection
list = User.find_by(id: params[:user_id]).contact_lists.find_by(id: params[:last_contact_list_id])
user_selection = params[:Digits]
#client = Twilio::REST::Client.new(##account_sid, ##auth_token)
case user_selection
when "1"
#output = "say something."
twiml_say(#output, true)
when "2"
twiml_dial("+1805XXXXX")
when "3"
#output = "Bye Bye..."
twiml_say(#output, true)
end
end
Let me know if this helps!

Pass multiple objects into action mailer/email contents in rails

Would like to find out how to pass multiple objects into action mailer/email contents in rails. I have no issues passing in #announcement, but not sure how to pass in #post and also #user info.
announcement_controllers.rb
def create
#post = Post.find_by slug: params[:post_id]
#announcement = #post.announcements.build(announcement_params)
#announcement.creator = current_user
if #announcement.save
flash[:notice] = 'Your announcement was created.'
AnnouncementMailer.announcement_alert(#announcement, #post).deliver
redirect_to :back
else
flash[:notice] = 'Unable to create announcement. Make sure you have enter information.'
redirect_to :back
end
end
announcement_mailer.rb
class AnnouncementMailer < ActionMailer::Base
binding.pry
default to: Proc.new { Signup.where(post_id: #post.id, user_id: current_user.id).pluck(:email) },
from: "#{#post.slug}#fundspace.announcement.com"
def announcement_alert(announcement, post)
#announcement = announcement
#post = post
mail(subject: "#{#post.slug}: #{#announcement.title}")
end
end
binding.pry
1: class AnnouncementMailer < ActionMailer::Base
=> 2: binding.pry
3: default to: Proc.new { Signup.where(post_id: #post.id, user_id: current_user.id).pluck(:email) },
4: from: "#{#post.slug}#fundspace.announcement.com"
5:
6: def announcement_alert(announcement, post)
7: #announcement = announcement
[1] pry(AnnouncementMailer)> #post
=> nil
[2] pry(AnnouncementMailer)> #announcement
=> nil
[3] pry(AnnouncementMailer)> #user
=> nil
binding.pry to check on #post in announcement_mailer.rb returns nil. Not sure why. Thanks in advance.
This is a classic case of your debug code giving you the wrong impression. 😃 Your #post is getting passed in fine - but it's happening after the call to binding.pry.
You pass in your post to announcement_alert, which sets it as an instance variable. If you updated that method to look like this, you should see it set fine:
def announcement_alert(announcement, post)
#announcement = announcement
#post = post
binding.pry
mail(subject: "#{#post.slug}: #{#announcement.title}")
end
(You're not checking that post is an object in your mailer, so it's possible for other code to pass nil. That shouldn't be a problem in this case, though - Post.find_by will return nil if there are no matches, but your #post.announcements.build would fail if it had.)
This confusion over where #post gets set is going to cause problems in your default line, too. Statements outside of a method - like your binding.pry and your default to: - get run when the class is evaluated. Statements inside a method - those inside def announcement_alert - don't run until that method is called. And, as we saw above, #post isn't defined until you call announcement_method.
Here's your current default statement:
default to: Proc.new { Signup.where(post_id: #post.id, user_id: current_user.id).pluck(:email) },
from: "#{#post.slug}#fundspace.announcement.com"
Your to: parameter is set to a Proc, which is great - even though it references #post, because it's a Proc it doesn't run until it's needed. You'll have set #post at that point.
Your from: parameter, on the other hand, is just a string. It's outside of a proc. As a result, it tries to evaluate #post.slug immediately - and there's no #post set yet, leading to an error. Changing it to this fixes it:
default to: Proc.new { Signup.where(post_id: #post.id, user_id: current_user.id).pluck(:email) },
from: Proc.new { "#{#post.slug}#fundspace.announcement.com" }

Rails - save to database from external JSON on create

I am attempting to update database fields from an external JSON response using Ruby on Rails. I would like this action to take place upon creation of a new record, as the data is relatively static. In the future I'll need to tackle the ability to refresh the data, but that is for another day.
I have created the rails scaffolding using:
rails generate scaffolding hotel hotelId:integer hotelName:string hotelCity:string
I would like to create a new record using only the hotelId, send the hotelId in my URI request, and then update the hotelName and hotelCity field.
I'm stuck on both sending the request using the hotelId field, and saving the results.
hotel.rb Model:
class Hotel < ActiveRecord::Base
def self.save_data_from_api
api = Expedia::Api.new
response = api.get_information({:hotelId => '#hotelID'})
hotel_data = response.body
hotel_parsed = JSON.parse(hotel_data.to_json)
h = Hotel.new
h.hotelName = hotel_parsed['HotelInformationResponse']['HotelSummary']['name']
h.hotelCity = hotel_parsed['HotelInformationResponse']['HotelSummary']['city']
h.save!
h
end
end
Included in my hotels_controller.rb
def new
#hotel = Hotel.new
#hotelID = Hotel.hotelID
end
I have not updated the new.html.erb View because I did not know how or where to call the save_data_from_api method.
Incidentally, the Expedia API gem I'm using is located here: https://github.com/zaidakram/expedia
Like:
class Hotel < ActiveRecord::Base
before_save :save_data_from_api
def save_data_from_api
return if hotel_id.blank?
api = Expedia::Api.new
response = api.get_information({:hotelId => hotel_id})
hotel_data = response.body
hotel_parsed = JSON.parse(hotel_data.to_json)
self.hotel_name = hotel_parsed['HotelInformationResponse']['HotelSummary']['name']
self.hotel_city = hotel_parsed['HotelInformationResponse']['HotelSummary']['city']
end
end
and then use like Hotel.create(hotel_id: '33').
Note that I've changed your AR attribute names to be more Ruby-ish.
EDIT
Depending on what you're doing with your application, it may not be necessary or the best idea to add hotels from a controller. You might want to just load them from rails console, or, if you have a list of hotel IDs, using a Rake task.
However, if you want to load them from a controller, you can have:
# in controller:
def new; #hotel = Hotel.new; end
def create
# note: if you're using Rails 4, use strong params here
#hotel = Hotel.new(params[:hotel])
respond_to do |format|
if #hotel.save
format.html { redirect_to #hotel, notice: 'Hotel was successfully created.' }
else
format.html { render action: "new" }
end
end
end
And in your new.html.erb, something like:
<%= form_for #hotel do |f| %>
<%= f.text_field :hotel_id %>
<%= f.submit 'Submit' %>
<% end %>

best way to prevent each on a nil variable on rails 4

I have a query that is checking if a certain values exist in the DB and returns an array if they exist
#canEditTask = Accessor.where("accessor_id = ? AND access_right = ?", current_user, true)
The problem is that this can return nil
#taskEdit = #canEditTask
but my each method in my html still fails due to nil undefined methodeach' for nil:NilClass`
.
<% #taskEdit.each do |task| %>
<%= task.id %>
In that case what is the best way to prevent a nil from breaking my code?
Edit
Controller code
def index
#canEditTasks = Accessor.where("accessor_id = ? AND access_right = ?", current_user, true)
end
def show
#taskEdit = #canEditTasks
rescue ActiveRecord::RecordNotFound
render :file => 'public/404.html'
end
View code
<div>
<% #taskEdit.each do |task| %>
<%= task.id %>
<% end %>
</div>
You are setting #canEditTasks in your index method and trying to use it in your show method... if you are confused by this you should probably go back to the basics and read/watch some Rails tutorials (sorry if I'm missing something here...).
When you assign #taskEdit = #canEditTasks in the show action, #canEditTasks is nil, which means #taskEdit is also nil.
Actions are run one at a time, it seems your code is expecting index to run first, and then show would run after that. That isn't how Rails works by default. If you want to run some code that is shared between several actions, I would suggest a before_filter.
before_filter :set_can_edit_tasks
def index; end
def show
#taskEdit = #canEditTasks
rescue ActiveRecord::RecordNotFound
render :file => 'public/404.html'
end
private
def set_can_edit_tasks
#canEditTasks = Accessor.where("accessor_id = ? AND access_right = ?", current_user, true)
end
I would prefer to use a .to_a after the active record where. so no error when a nil array is looped ;) avoids condition in views.

Rails: checking modified fields

First, I've generated scaffold called 'item'
I'd like to check which fields of the item are modified. and I've tried two possible attempts, those're not work tho.
First Attempt!
def edit
#item = Item.find(params[:id])
#item_before_update = #item.dup
end
def update
#item = Item.find(params[:id])
# compare #item_before_update and #item here, but #item_before_update is NIL !!!
end
Second Attempt!
I looked for the way passing data from view to controller and I couldn't.
edit.html.erb
<% #item_before_update = #item.dup %> # I thought #item_before_update can be read in update method of item controller. But NO.
<% params[:item_before_update] = #item.dup %> # And I also thought params[:item_before_update] can be read in update mothod of item controller. But AGAIN NO
<% form_for(#item) do |f| %>
# omitted
<% end %>
Please let me know how to solve this problem :(
Attributes that have changes that have not been persisted will respond true to changed?
#item.title_changed? #=> true
You can get an array of changed attributes by using changed
#item.changed #=> ['title']
For your #update action, you need to use attributes= to change the object, then you can use changed and changed? before persisting:
def update
#item = Item.find(params[:id])
#item.attributes = params[:item]
#item.changed #=> ['title']
... do stuff
#item.save
end

Resources