Simple Ruby on Rails Button Action - ruby-on-rails

I have a method in a helper file that I want activated only when a button is pressed.
def add_f01
#count = Count.find_by_user_id(#user)
#car = Car.find_by_user_id(#user)
#car.toggle!(:f01)
#count.increment!(:v01)
end
How do I do it, please?

I've created a working app here: https://github.com/noahc/stackoverflow
Pull it down and play around with it so you can learn how it works.
Essentially you need the following:
#routes.rb
match 'f01', to: 'users#call_app_controller'
# Anywhere in your view. I have it in index.html.erb of users
<td><%= button_to 'change name', f01_path(user: user)%></td>
#Application controller
def add_f01(user)
user.first = "changed in Application Controller"
user.save
end
#users_controller
def call_app_controller
#user = User.find(params[:user])
add_f01(#user)
redirect_to users_path
end

Related

Destroy user - with custom authentication (rails)

Quick question: I was following this tutorial where they built user authentication system instead of using devise.
My issue is the tutorial misses the destroy action in which devise has ready and does so well.
My create action is
User_controller.rb
def create
#user = User.create(user_params)
session[:user_id] = #user.id
if #user.valid?
flash[:notice] = "You've successfully Created Your Account! Welcome!"
redirect_to root_path
else
flash[:notice] = "Opps Something went bad, :/ Try again please"
render action: 'new'
end
end
I really hope this is not a total nuub question event though I am one. But can somebody offer some tips for a destroy action ? and also how would that action appear in routes and through a link_to method. I want to create a deactivate page that gives a send off and the user is able to cancel their account. Any cool tips toward the deactivate page on the side will be much appreciated.
The Hartl rails tutorial covers this quite well IMO. Once you have the destroy action defined in your controller, you could create a link to deactivate their account calling the destroy action and redirect to the home page, or a goodbye page. As long as users is listed as a resource in your routes, you shouldn't need to modify your routes as DELETE is a standard CRUD command.
https://www.railstutorial.org/book/updating_and_deleting_users
for example:
user_controller
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
view
<%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
For the deactivate page, maybe you can add a boolean column in your users table, say is_active,
and another controller action for deactivation, say deactivate, which will just set the is_active column as false for that user.
see sample routes.rb for the route.
#ncarroll 's sample is correct, for the routes, if you have in your routes.rb:
Rails.application.routes.draw do
resources :users do
put :deactivate
end
end
This will automatically create routes for the RESTful actions, which includes destroy.

undefined method paypal_url in 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.

Calling Methods in Rails - From Controller or from Views

I have a problem with calling methods. Here is the code from one of my Controllers:
class MethodsController < ApplicationController
def details
#title = "User Details"
#fname = params[:first_name]
#lname = params[:last_name]
#exam_no = params[:exam_no]
if #fname && #lname then
#candidate = Candidate.create({:first_name => #fname, :last_name => #lname,:exam_number => #exam_no})
grades #This method call doesn't work
end
end
def grades
#title = "Enter Grades"
#candidate = Candidate.find(:last)
#grades = params[:grades]
#candidate.update_attributes({:grades => params[:grades]})
end
end
The details method works fine, clicking the 'submit' button on the 'details' view creates the Candidate and I can 'link_to' the next page.
What I really want to do is: Click 'submit' and be automatically taken to the next view, 'grades' (which is also shown above). I thought a method call to 'grades' in 'details would work, but it doesn't. The 'grades' page title appears, but the view for 'details' still remains.
Is there some way to do this? Possibly call the 'grades' method from 'details' view? I know that's not best practice, but I'm stuck. (I tried #controller.grades but I get a NoMethodError - #controller is nil). I also tried render 'grades' but of course while it renders the view, it doesn't execute the code.
You might be looking for redirect_to instead of render
Redirect_to :action => 'grades'

Rails way to render different actions & views based on user type?

I have a couple different user types (buyers, sellers, admins).
I'd like them all to have the same account_path URL, but to use a different action and view.
I'm trying something like this...
class AccountsController < ApplicationController
before_filter :render_by_user, :only => [:show]
def show
# see *_show below
end
def admin_show
...
end
def buyer_show
...
end
def client_show
...
end
end
This is how I defined render_by_user in ApplicationController...
def render_by_user
action = "#{current_user.class.to_s.downcase}_#{action_name}"
if self.respond_to?(action)
instance_variable_set("##{current_user.class.to_s.downcase}", current_user) # e.g. set #model to current_user
self.send(action)
else
flash[:error] ||= "You're not authorized to do that."
redirect_to root_path
end
end
It calls the correct *_show method in the controller. But still tries to render "show.html.erb" and doesn't look for the correct template I have in there named "admin_show.html.erb" "buyer_show.html.erb" etc.
I know I can just manually call render "admin_show" in each action but I thought there might be a cleaner way to do this all in the before filter.
Or has anyone else seen a plugin or more elegant way to break up actions & views by user type? Thanks!
Btw, I'm using Rails 3 (in case it makes a difference).
Depending on how different the view templates are, it might be beneficial to move some of this logic into the show template instead and do the switching there:
<% if current_user.is_a? Admin %>
<h1> Show Admin Stuff! </h1>
<% end %>
But to answer your question, you need to specify which template to render. This should work if you set up your controller's #action_name. You could do this in your render_by_user method instead of using a local action variable:
def render_by_user
self.action_name = "#{current_user.class.to_s.downcase}_#{self.action_name}"
if self.respond_to?(self.action_name)
instance_variable_set("##{current_user.class.to_s.downcase}", current_user) # e.g. set #model to current_user
self.send(self.action_name)
else
flash[:error] ||= "You're not authorized to do that."
redirect_to root_path
end
end

Session Issue in rails?

Suppose this is my users controller:-
class UsersController < ApplicationController
def show
#user = session[:user]
end
def prepare
session[:user]= User.find(:first)
redirect_to :action => 'show'
end
def update
#user = session[:user]
#user.name = 'rai'
redirect_to :action => 'show'
end
end
View for show.html.erb
<%= #user.name %>
Show page
<%= link_to 'Update', :action=> 'update' %>
Now Explaining the issue:---
Suppose first time user opens the browser with
http://localhost:3000/users/prepare
o/p will be:---
Mohit Show page Update // supposing user table has values mohit as name
Now when he click on update he will get as output like this:--
rai Show page Update
But this should not happen cause
firstly when are at prepare action where value is fecthced from db and its mohit. and then he is redirected to show ie displying the values from session. ie mohit
Now when user click on the update he is redirected to update when value from session is stored to a user instance and the name attribute of that user instance has been modified to rai. and finally redirected to show page.
Now in this page when user's name is displayed its showing rai.. thats the QUESTION why??
cause session should store the same mohit value cause we havnt made any change in session..
When you are doing
#user = session[:user]
#user variabe is assigned reference to the object session[:user], not the copy of it.
So when you are modifying #user, session[:user] is also modified, as they are essentially the same object.
I'm not sure, but I think it is something with hashes and classes and about copying them. So when you do:
#user = session[:user]
You are not making a copy of object but it is something likre reference in C++, both #user and session[:user] are reffering to the same object, so when you modify one, you get both modified.
Example from console:
a = {}
a[:user] = User.first
a[:user].firstname # => "Mohit"
b = a[:user]
b.firstname = 'rai'
a[:user].firstname # => 'rai'
a[:user] = User.first
a[:user].firstname # => 'Mohit'

Resources