RoutingError on empty field, conflicting with friendly_id - ruby-on-rails

I have a edit form for #users.
In there I have a text_field :username
<%= form_for #user, :url => { :action => "update" } do |f| %>
<%= render 'shared/error_messages', :target => f.object %>
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username %>
</div>
In my User model I use the friendly_id gem, set to :username as well. So my urls look like domain.com/users/:username instead of :id.
has_friendly_id :username
Now in my application layout, I also use #user.username in my navigation to link to the profile.
All works well, EXCEPT if I leave my :username field empty on save. It fails to save cause of validations,
validates :username, :presence => true, :uniqueness => { :case_sensitive => false }, :length => { :maximum => 50 }
and tries to render "edit" again. But to render "edit" we need the username to create the link in the navbar. And apparently it's passed on as username => "", even though it rightfully so failed to save and proper validations are in place.
def update
#user = current_user
if #user.update_attributes(params[:user])
flash[:success] = "Account updated."
redirect_to :back
else
#title = "Edit"
render "edit"
end
end
So I end up with a RoutingError:
No route matches {:action=>"show", :controller=>"users", :id=>#<User id: 6, username: "", persistence_token: "c2f2545659c186131537155347f46f7da5eb0d51b27707e71da...", created_at: "2011-03-14 14:26:48", updated_at: "2011-03-15 01:54:33", email: "test#test.com", crypted_password: "0d6489b1447d278bc4f7c86bab13787f226a10a302b43ec02ff...", password_salt: "Lq2G80iSVeaitB5PDwf", perishable_token: "Tm7Jzyq8QutfaxL3JLZ8", active: true>}

First of all, redirecting to :back, even if you successfully change the username, will likely fail because the URL itself is going to be different. So you should probably do
redirect_to #user
instead.
If you want to use the username field as the basis of a friendly_id, then it's probably best to not let it be blank, which you could enforce by adding a validation to the model:
class User < ActiveRecord::Base
...
validates_presence_of :username
...
end
Alternatively, if for some reason in your app makes sense to have them blank, you can force Rails to generate the URL based on the numeric id rather than the friendly_id in these cases.
To do this, you would need to set username value to nil rather than blank, and then either do
redirect_to #user
or
redirect_to user_url(#user)
In this case you'll also want to use the :allow_nil => true option to has_friendly_id.
I'm the author of FriendlyId, if this doesn't solve your problem feel free to send a message to FriendlyId's Google Group or to me personally at norman#njclarke.com, and I'll try to help you out.

You don't really need to re-render the edit screen if your validation fails.
It'd probably work better if you updated your page using ajax and use a remote_form_for (Rails 2) or form_for :remote => true (Rails 3) when submitting your form. That way if your form passes the validation you can just redirect the user like you're trying to do, but you don't need to actually leave the page if your validation fails, you can just send the validation message back to the form.
Simone Carletti's blog has a pretty decent example on how to do it.
http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/
Ryan Bates has put up a simple example of how to use it as well.
http://railscasts.com/episodes/205-unobtrusive-javascript

Related

Pass a text_field custom parameter to a link_to paypal IPN

I'm trying to send an email to the client when he successfully makes a transaction using paypal.
I've already manage to send the custom email parameter to paypal in a custom parameter they provide.
What I have right now
My product model:
class Product < ActiveRecord::Base
# This defines the paypal url for a given product sale
def paypal_url(return_url, cancel_return, useremail)
values = {
:business => 'your_business_email#example.com',
:cmd => '_xclick',
:upload => 1,
:return => return_url,
:rm => 2,
:cancel_return => cancel_return,
:custom => useremail
}
values.merge!({
"amount" => unit_price,
"item_name" => name,
"item_number" => id,
"quantity" => '1'
})
# For test transactions use this URL
"https://www.sandbox.paypal.com/cgi-bin/webscr?" + values.to_query
end
has_many :payment_notifications
end
here, I'm passing a parameter for the :custom object which I have it hardcoded in the button link_to helper here:
<%= link_to 'checkout', #product.paypal_url(payment_notification_index_url, root_url, 'testing#testing.com') %>
This works perfectly, and I am able to store the custom email in the database:
class PaymentNotificationController < ApplicationController
protect_from_forgery except: [:create]
def create
# #payment = PaymentNotification.create!(params: params, product_id: params[:invoice], status: params[:payment_status], transaction_id: params[:txn_id] )
#payment = PaymentNotification.create!(params: params, product_id: 1, status: params[:payment_status], transaction_id: params[:txn_id], email: params[:custom] )
# render nothing: true
if #payment.status == 'Completed'
PaymentTransactions.success(#payment).deliver_now
redirect_to root_url, notice: 'Success!'
else
redirect_to root_url, notice: 'Error'
end
end
end
Question
How do I get the client to input their email in a field and pass that value into the parameters of the link_to so that paypal return the email so I can store it in the database and send an email to the client?
Thanks
You should not use link_to, but form_tag with method: :get
<%= form_tag (#product.paypal_url(payment_notification_index_url, root_url, :custom)),method: :post do %>
<%= text_field_tag :custom %>
<%= submit_tag 'checkout' %>
<% end %>
This might be more than what you're expecting...but read on.
Before you dive further into the implementation, keep in mind that, you're using the sandbox version of Paypal for testing, and in production, you'd want the paypal_url to return an encrypted url for the user as to avoid tampering of the transaction, such as changing the price (more details at Railscast #143).
Now, realize that any approaches on the client-side via javascript to get the user email field and modify the link will not be secure as the link should be generated from your server after encryption (and you'd need to pass in the user email as part of the call).
So, what can you do? Use ajax to send the request to the server containing the parameters (e.g. return_url, user_email, etc..), and respond in the server with an encrypted link. Then, you can use javascript to replace the link and allow user to click that instead.
As you realize, the implementation above is very general and any answer would not suit your specific case. You should keep the above in mind as you'd be required to do that anyway down the road.

How to get an Id value from association rails

At this time I need to get and id value from an association
Because I create a new note, but i can assign this note to whoever i want, then I have it this way
<%= f.association :user,
:label => false,
:selected => current_user.id,
:required => true,
:input_html => {
:class => 'span4',
:disabled => true,
:style => "float:right",
:id => "usuario"} %>
And the controller create method is this way
def create
#note = Note.new(note_params)
#note.user_id = params[:user]
render :action => :new unless #note.save
end
But when I press the submit button everything save unless the value for the column :user_id
I have tried with params[:user_id] but it doesn't work
Thanks for your help and sorry for my english
First you need to remove the attribute disabled from your field, a disabled field isn't sended by your form (look at Disabled form fields not submitting data).
And, your user_id should be placed in something like params[:note][:user_id], take a look at server log and search for user_id right after you send a POST to server, there be something like:
Started POST "/note" for ::1 at 2013-07-18 15:22:34 +0000
Processing by NoteController#create as */*
Parameters: {"note"=>{..., "user_id"=>"1", ...}}

How to allow a person to register for an 'event', and creates a 'user' at same time in Rails

I've created a simple Rails application where users can register to attend events. To create a pleasing user experience, an unidentified user can browse the events and then if they see one they'd like to event they can click 'register for the event'. Using Twitter Bootstrap, the application then presents the user with a modal (popup) asking them to register first, to attend the event.
The form on the modal is as follows:
simple_form_for #user do |f|
f.input :name, :placeholder => "Name", :label => false
f.input :email, :placeholder => "Email", :label => false
f.input :postcode, :placeholder => "Postcode", :label => false
hidden_field_tag :event_id, #event.id
f.button :submit, "Sign me up for this event"
end
So, you can see that basically I pass in an event_id value to the user controller's create action. To handle this the create action becomes:
def create
if params[:event_id].blank?
event_registration = false
else
event_id = params[:event_id].to_s
event_registration = true
end
if event_registration == true
# The user is being created as part of signing up to an event
#user_check = User.find_by_email(params[:user][:email])
unless #user_check.nil?
# The user already exists, but the visitor forgot
#user = #user_check
else
# The user is a new sign up
#user = User.new(params[:user])
end
# Now create the attendance for the user
#event = Event.find(event_id)
#attendance = #event.attendances.new
#attendance.attendee = #user
#attendance.save
redirect_target = event_attendance_thank_path(#event, #attendance)
else
# The user is being created cleanly
#user = User.new(params[:user])
end
if #user.save
redirect_to root_path, notice: "Thanks for signing up, check your email"
else
# We should destroy the failing attendance?
redirect_to root_path, alert: "Something's up with the signup. Have you already registered with this email address?"
end
end
To me, handling this level of complexity in the controller feels messy, and I'm wondering what better ways I might go about this?
Any help or pointers to refactor this would be greatly appreciated.
If it is possible for users that are already signed and logged in to mark their attendance for events, you should use the same piece of code in both places. Just create helper that will mark users' attendance and call it from both UsersController#create and Events#attend (or whatever it is called) actions.
Now -- if you have heard of "fat model, skinny controller" pattern, you are probably starting to notice it is a place you could use it.
Just create User model method to attend some event, that will accept id, or event itself as an argument. This way you could simply write in your controller:
User.create(...).tap do |user|
user.attend(params[:event_id]) if params[:event_id]
end

Ruby on Rails: Send email from show page

I am a Rails noob and have a problem sending an email from a show page. There are several contact form tutorials out there but I cannot find one where I send an email from a page like a 'show' page. I have big errors in my routes I believe. In the model I state that Users have several Promotions and on the promotions show page I want to allow the current_user to send an email to #user.
here is app/mailers/quote_mailer.rb
class QuoteMailer < ActionMailer::Base
default :from => "tim#example.com"
def quote_mail(promotion)
#user = user
mail(:to => user.email, :subject => "You have an inquiry homeboy!")
end
end
In promotions_controller I put this action which I think might be wrong:
def quotedeliver
QuoteMailer.quote_mail.deliver
flash[:notice] = 'report sent!'
redirect_to root_path # or wherever
end
Here is the form that I use to send the email (the :url is probably wrong but I dont know how it should look)
<%= form_for quote_mail, :url => quotedeliver_promotion_path(promotion), :html => {:method => :put } do |f| %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
I would love some help with this. I cannot find anything like it on stackoverflow, I have been trying for days. Thank you!
You are probably missing the route in config/routes.rb
you can define it like
post '/quotedeliver_promotion' => 'promotions#quotedeliver', :as => quotedeliver_promotion
Note that quotedeliver has to be rewritten quote_deliver to follow ruby syntax conventions. When you call
QuoteMailer.quote_mail.deliver
You are not giving the parameter, so try this
QuoteMailer.quote_mail(current_user).deliver
And change your method with
def quote_mail(user)
mail ....
end
and you are all good
There are some excellent screen casts (through Railscasts) regarding sending e-mail http://railscasts.com/?tag_id=28.
One last thing, do not attach your mail sending method to a show action (if you are doing currently), the reason is show action is only for view something and users might be refreshing that page, So if you attach a mailer to that, mails might go out for each refresh.
def quote_mail(promotion)
#user = user
mail(:to => user.email, :subject => "You have an inquiry homeboy!")
end
from where you are access user variable, it should be promotion i think.

Update fails with namespaced model

I have an update form in Rails 3 for admin users that fails silently, despite having validations. It was working previously, but when I moved everything to a namespace, it no longer saves.
Here is the relevant code from my controller:
def update
#admin = Admin::Admin.find(params[:id])
respond_to do |format|
if #admin.update_attributes(params[:admin])
flash[:success] = "'#{#admin.name}' was successfully updated."
format.html { redirect_to admin_admins_path }
else
format.html { render action: "edit" }
end
end
end
And the model (unfinished, but previously working):
class Admin::Admin < ActiveRecord::Base
validates :name, :presence=>{:message=>"Name can't be blank"}
validates :email, :presence=>{:message=>"Email can't be blank"},
:length => {:minimum => 3, :maximum => 254, :message=>"Email must be between 3 and 254 characters"},
:uniqueness=>{:message=>"Email has already been registered"},
:format=>{:with=>/^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :message=>"Email must be a valid email format"}
validates :password, :presence=>{:message=>"Password can't be blank"}
end
And the first part of the form partial:
<%= form_for(#admin) do |f| %>
Everything loads properly, but when I try to save, my validations are ignored and it redirects to the index page with a success message, but without saving the data. I have a feeling I'm missing something to do with namespaces, but I'm not completely sure what the problem is. Could it be looking for the model in the base model directory?
Did you inspect the params? I could imagine that params[:admin] does not contain the forms values anymore.
So, VirtuosiMedia and I stepped through it, and RoR adds an "admin_" to represent the Admin:: namespace, so we had to look for params[:admin_admin].

Resources