How to pass variable from instance method into controller? - ruby-on-rails

I need to call method for each user(admin part), which has email parameter. It is a function for paying in PayPal, but I can't use redirection in instances.
Code from my view payments.erb:
% #users.each do |user| %>
<li>
<%= user.email %>
<%= link_to "Pay", user.pay(user.email) %>
</li>
Code of pay method
def pay email
//making post request to PayPal
//res = clnt.post(uri, data, header)
//if res.status ==200
//redirect_to PayPal
//else redirect_to :back
end
How I can pass parameters or how can I reorganize this all ?
Do I need to create an action in pages controller, or can I use some after_call_pay function ?

It isn't the controllers job to respond to instance methods. It's the controllers job to respond to requests.
So you want to be able to link_to an action that responds to mydomain.com/users/1/pay or something like that.
In routes
resources :users do
member do
post 'pay'
end
end
then in your controller
def pay
#user = User.find(params[:id])
#route user to paypal or somewhere else based on some condition
end
And finally in the view
<%= link_to "Pay", pay_user_path(user) %>

I think you should be handling this in a form rather than a link.
If payment is a method associated with a user object then you would want to do something like this:
View -
<%= form_for #user, :url => { :action => "make_payment" } do |f| %>
#any form fields associated with making the payment (ie credit card number)
<%= f.submit %>
<% end %>
This would route the form to the Users_controller and to an action named "make_payment". Make sure to provide a route to this action in your config/routes file as this will not be reachable if you are using the standard resourceful routing.
Controller -
def make_payment
#user = User.find(params[:id])
user.submit_payment(params[:credit_card_num])
redirect_to #user
end
That should accomplish what you are looking to do. Check here for some more explanation on the rails form helpers http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for

Related

Generate method dynamically using strong params in Rails

Is it possible to generate a dynamic method using the strong parameter I get from my view?
In my view I will generate a different path according to the card the user clicks on. Then, in the controller I want to generate a dynamic method using the parameter obtained from the view, but I'm not sure how to write that. Thanks!
show.html.erb
<div class="branch-names">
<% #branches.each do |branch| %>
<div>
<%= image_tag "cat.jpeg" %>
<%= link_to "#{branch.name} Posts", send("#{branch.branch}_posts_path") %>
</div>
<% end %>
</div>
posts_controller.rb
def self.define_category(name)
define_method(name) do |params[:id]|
#posts = Post.where(category_id = params[:id])
end
end
define_category("#{params[:id]}")
You shouldn't define method based on user input. It may cause security issue, and for sure it causes performance penalty related to method cache invalidation.
Instead you can create one method that have an alternarive on params[:id] and then decide what to show to the user:
class MyController
def branches
case params[:id]
when('cat')
do_cat_stuff
when('dog')
do_dog_stuff
end
end
end
For having routes like /posts/cats you do not have to add dynamic methods. Think of branch like of an id of category:
routes:
resources :post_categories, only:[:index, :show]
view:
...
<%= link_to "#{branch.name} Posts", post_category_path(branch.branch) %>
PostCategories controller:
def show
#posts = Post.where(category_id: params[:id])
end
Also you can make posts a nested resource under categories and use a more RESTful structure with /post_categories/some_branch/posts mapping to posts#index

Ruby on Rails - redirect_to

I'm having some trouble understanding the redirect_to statement.
I have a model "Book" (with an boolean attribute "read")and a controller "books". Now I created a second controller "Admins" having to methods: index and change.
The index view just renders a list off all Books with a link to the change method:
<% #Books.each do |d| %>
<%= d.title %><br>
<% if d.read==true %>
<%= link_to "mark unread", change_path(:id=>d.id)%>
<% else %>
<%= link_to "mark read", change_path(:id=>d.id)%>
<%end %>
Now the change method just changes the "read" attribute:
#book=Book.find(params[:id])
if #book.read==true
#book.update_attributes(:read => false)
else
#book.update_attributes(:read => true)
end
redirect_to action: "index"
The Problem is: rails tries to redirect me to the show action using the :id as a parameter...(perhaps because the change_url is /admins/change?id=3)
But I just want to be directed back to the index view "/admins"
is there a way? it seems like rails always tries to redirect to the view action if there is an id as a parameter
Thanks alot
PS: the routes.rb contains resources:admins and resources:books
Use this
redirect_to :controller => 'admins', :action => 'index'
Or
redirect_to admins_url
The above two will direct you to the index page of AdminsController. There is no way that Rails would route it to show action UNLESS you are redirecting to show action from the index action of AdminsController. Since, you did not share index action code of AdminsController, I would recommend you to check there.
If you want a clear explanation of redirect_to ... checkout
https://gist.github.com/jcasimir/1210155
I had a kind of similar issue some days ago. I would suggest to do this within the form where you list the books and the mark/unmark checkboxes.
<%= form_for #book,:url => book_index_path do |f| %>
This worked fine for me, when I set up a site where you create data and the user is immediately redirected to the same page (incl. success/error message).. to do a kind of
human batch-processing.

Two Buttons in Rails

I'm trying to get 2 buttons to work in rails for the same form. I have a login form with both an add user and signup button. I have 2 methods in my controller that already handle these 2 different requests.
However, I read the suggestions about using an additional parameter to parse to determine which button was called. For this solution wouldn't you need a level of indirection with another controller method to do the parsing? I read that having a controller call another controller isn't good MVC practice. In this case would calling another method within the MVC controller class be a bad practice?
My form:
<%= form_tag("users/delegate", :method=>"post") do %>
<%= label_tag(:user, "Username:") %>
<%= text_field_tag(:user) %>
<br/><br/>
<%= label_tag(:password, "Password:") %>
<%= password_field_tag(:password) %>
<br/><br/>
<%= submit_tag "Login", :name=>'login' %>
<%= submit_tag "Add User" %>
<% end %>
Also, how do I pass in the arguments from the post request into the other method? I
essentially did but the arguments are not being passed. Do I need to pass in params to the other method? Is it a global variable?
def delegate
if params[:login]
login_post()
else
add_post()
end
end
def login_post
user = params[:user]
password = params[:password]
errCode = UserModel.login(user,password)
if (errCode>0)
count = errCode
errCode = 1
end
final_obj = {:errCode=> errCode, :count=>count}
respond_to do |format|
format.json { render :json=>final_obj, :status=>200}
end
end
You should do like this:
def delegate
if params[:login]
login_post(params[:user], params[:password])
else
add_post()
end
end
def login_post(user, password)
#do your things
end

How do I use another value of a key in a hash if the first one doesn't exist, like some type of fallback in ruby/rails?

Basically I have a follow button and when click the page refreshes and I show an unfollow button in place. Below is the code I use to render the particular form needed:
follow_forms partial:
<% unless current_user?(#user) %>
<% if current_user.following?(#user) %>
<%= render 'relationships/partials/unfollow' %>
<% else %>
<%= render 'relationships/partials/follow' %>
<% end %>
<% end %>
Any I changed the form to an ajax form because I don't want the page refresh and on success of the form submission I'd like to replace the follow button/form with an unfollow button/form. This isn't straight forward because only 1 form shows at a time so I can't use my jquery selector to find this form anyway.
What I decided to do was create a new action that renders the follow_form partial this way the appropriate form will be available for me to manipulate with my jquery selector.
The new action:
class RelationshipsController < ApplicationController
def get_follow_form
respond_to do |format|
format.html { render :partial => 'relationships/partials/follow_form_ajax' }
end
end
end
The problem now is that I don't have access to the #user instance variable. That doesn't matter to much because I can get the user who was just followed via the jquery success data then pass that as data in the new ajax call to get_follow_form_url and then pass that info into the partial as a local variable.
I still have an issue with the #user instance variable not being available. Which brings me to my question.
How can I make another value be used if the instance variable isn't nil/doesn't exist?
The form for following:
<%= form_for current_user.relationships.build(:followed_id => #user.id), :remote => true do |f| %>
<%= f.hidden_field :followed_id %>
<%= f.submit "Follow", :class => 'followButton' %>
<% end %>
Can I do something like this
:followed_id => #user.id <-if this doesn't exist use this-> user.id
There are other ways around this like creating new partials that are only used for this whole situation or creating some messy if statements but I feel like creating duplicate forms should be my very very very last option.
I look forward to you solutions thanks
Kind regards
There's a very simple way to do this, assuming you have your 'fallback' ID:
:followed_id => #user.present? ? #user.id : fallback_id
Use something like the andand gem or just try and a logic expression:
:followed_id => #user.andand.id || user.id
Even without that you can use identical logic, and certainly don't need multiple partials:
:followed_id => (#user && #user.id) || user.id
But as Frederick says, if you have a replacement value for the object already, couldn't you just set it?

What is the best way to route a static controller in Rails?

I have a static_controller that is in charge of all the static pages in the site and works as follows in routes.rb:
map.connect ':id', :controller => 'static', :action => 'show'
I have a static page called about that among other information, has a contact form.
I currently have a contacts_controller that is in charge of inserting the contact information to the database.
Inside my routes.rb file, I have:
map.resources :contacts
My contact form (simplified) looks like this:
<% form_for #contact do |f| %>
<p class="errors"><%= f.error_messages %></p>
<p>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</p>
<p class="buttons"><%= f.submit %></p>
<% end %>
Which in turn submits to the create action of my contacts_controller.
My create action looks like this:
def create
#contact = Contact.new(params[:contact])
if #contact.save
flash[:notice] = "Email delivered successfully."
end
redirect_to "about"
end
The problem is, is the that when I redirect back to my about page the error_messages for the form get lost (since the error_messages for the form only exist for one request, and that request ends upon redirect).
How would I go about preserving the error_messages and still linking the users back to the about static url?
Would a session/flash be sufficient (if so, what code would I use to pass error messages) or am I going about this whole thing wrong?
Thanks!
I think what might be going on is you need to render rather than redirect.
Redirect terminates the request, and tells the client to make a new request to a different address. That will lose your errors.
If your save attempt fails your want to complete the request by rendering the action again with the errors shown.
def create
#contact = Contact.new(params[:contact])
if #contact.save
flash[:notice] = "Email delivered successfully."
redirect_to #contact #make a new request for the address of the new record or some other address if you want
else
render :action => "new" #complete the request by rendering the new action with the #contact variable that was just created (including the #errors).
end

Resources