Rails: Custom built ban user functionality not working - ruby-on-rails

I am trying to ban a user, but it is not working as expected, probably because I have no clue what I am doing:
Routes:
resources :users do
collection do
post 'ban'
end
end
class UsersController < ApplicationController
def ban
#user = User.find(params[:id])
if current_user.admin?
#user.banned = true
#user.avatar = nil unless #user.avatar.nil?
#user.banned_by = current_user.full_name
#user.profile = nil unless #user.profile.nil?
#user.save
redirect_to current_user, notice: "User has been banned."
end
end
end
In my view:
<%= link_to "Ban User", ban_users_path(:id => #user.id), :method=>:post %>
For some reason, it passes the parameter "ban" and says cannot find user.

Your routes should be
resources :users do
member do
post 'ban'
end
end
Member routes act on a member, so your request would look like POST /users/1/ban (user #1 being the member). Collection routes are for acting on the entire collection, i.e., POST /users/ban. Your helper should turn into into ban_user_path(#user)
Also I don't think you need to check if their avatar/profile is nil before setting them to nil. Just set them to nil, there is no need to check. If they are already nil, there is no harm done by setting them to nil again.

Related

How to destory all users but current user(admin) in ruby

I have this setup where it destroys all users but i want it not to destroy current user which is admin.
controller.
def remove_all
User.destroy_all
redirect_to(admin_users_path, { flash: { success: 'You have wiped all the data on the website!' } })
end
navigation.html
<%= link_to "Nuke Button", remove_all_profiles_path, :method => :get %>
route:
resources :profiles do
member do
get :delete
end
collection do
get 'remove_all'
end
end
I know I have to add something to the controller just don't know what to add
I'm assuming you have access to the current_user in your controller (or if not that, you know the id of the current user somehow
User.where.not(id: current_user.id).destroy_all
Note: In Rails 7 you will also be able to do
User.excluding(current_user).destroy_all
Which is a bit nicer maybe, but this doesn't work yet.
https://blog.saeloun.com/2021/03/08/rails-6-1-adds-excluding-to-active-record-relation.html

Rails call a controller user-defined method

I am working with rails I have a controller name books and has a user defined method in it .I need to call this method so that i can see the output on console.And I dont want to call this method in helpers.
def approve
#user=current_user.users.find params[:id]
puts '#{#usery}'
end
Also I Have a link
<%= link_to 'approve',users_path,data: { :confirm => 'Are you sure to delete the folder and all of its contents?'} %>
.When i click on this link I want to call the above method on it .
You'll just need to define a route and call it through that:
#config/routes.rb
resources :users do
get :approve, on: :member
end
<%= link_to "Approve", users_approve_path(#user) %>
As #Rich suggested that, you can achieve it by member. Please note that when you'll create a member route in member block
resources :users do
member do
get 'approve'
end
end
then you'll get the params[:id]. Like
def approve
#user = User.find params[:id]
puts '#{#user}'
end
and when create a member route using :on then you'll get params[:user_id]. Like
def approve
#user = User.find params[:user_id]
puts '#{#user}'
end
Path will be same in both cases that is
<%= link_to "Approve", users_approve_path(#user) %>
Source Rails - Adding More RESTful Actions
Happy coding !!!

How to update a profile attribute by link_to

I want to update a Profile model attribute by using link_to. The Profile model have a lang column, and I want to change to :en.
I could find out that I should use method: :put.
<%= link_to t('english'), profile_path(profile: {lang: :en}), method: :put %>
But it's ends up with error:
ActionController::UrlGenerationError in StaticPages#home
Showing /Users/ironsand/dev/phrasebook/app/views/layouts/_header.html.erb where line #21 raised:
No route matches {:action=>"update", :controller=>"profiles", :profile=>{:lang=>:en}} missing required keys: [:id]
I have this line in routes.rb to use the path:
resources :profiles, only: :update
How can I enable the function like this?
I found a similar question, but the case is a bit difference.
Edit
class ProfilesController < ApplicationController
def update
return redirect_to root_path unless current_user # If user is not logged in, redirect to /
if current_user.profile.update(profile_params) # Don't forget about validation for lang in Profile model
redirect_to root_path
else
redirect_to root_path
end
end
private
def profile_params
params.require(:profile).permit(:lang)
end
end
You need to identify the profile somehow, that's why it asks for id. But you can update profile without id, you just need to improve update method:
def update
return redirect_to root_path unless current_user # If user is not logged in, redirect to /
if current_user.profile.update(profile_params) # Don't forget about validation for lang in Profile model
redirect_to success_path
else
redirect_to error_path
end
end
private
def profile_params
params.require(:profile).permit(:lang)
end
For route, try this:
resources :profiles, only: [] do
collection do
put :update
end
end
or just:
put '/profiles' => 'profiles#update'
Since you're updating a specific profile, you need to supply something that lets your controller know what profile you're updating.
As you can see from the error message generated, your controller can't identify which profile it is that you're asking to be updated. You need to supply the id of the profile in order to update it.
One way this could be achieved with link_to is as follows:
link_to t('english'), profile_path(id: #profile.id, lang: :en), method: :put
lang would then be available in your update action in params[:lang].

Button to Execute Ruby Without Javascript

Route
resources :cars do
collection do
get :f01a
end
end
Controller
class CarsController < ApplicationController
def f01a
#user = User.find(params[:id])
#count = Count.find_by_user_id(#user)
#count.increment!(:f02)
redirect_to #user
end
end
View
<%= button_to "add f01", f01a_cars_path %>
I can't get this to work. I need to execute this code from a button.
button_to sends a POST request, but your routing is setup to only accept GET requests. You should change it to:
resources :cars do
collection do
post :f01a
end
end
Since you're using params[:id] in your action, but not sending it in at all, you'll need to pass it in your button_to:
<%= button_to "add f01", f01a_cars_path(:id => something)
(Replace something with whatever ID you want to pass.)

Forgot password action, can I handle post with the same action name?

What is the rails way, to create seperate actions for get or post?
Is it possible to have the same name but decorate the action to only run if its a get or post?
e.g.
'get only'
def forgot_password
end
'post only'
def forgot_passord
end
Rails way is to have a resource -- Each method should have a responsibility.
resources :password_resets
And then you'll let a user reset their password by visiting the form:
link_to 'Lost your Password?', new_password_reset_path
And then the form will post to create a new password_reset... That will send an email with a link to show the password_reset.
form_tag(password_resets_path, :method=>:post) do
When the use enters their updated password, it will update the password_reset.
# in routes.rb
resources :password_resets
# in app/controllers/password_resets.rb
class PasswordResets < ApplicationController
def new
#user = current_user
# render new reset form
end
def create
#user = current_user
#new_password = User.generate_random_password
if #user.update_attributes(:password => #new_password)
UserMailer.password_reset(#new_password).deliver
flash[:notice] = 'Successfully reset your password, check your email!'
else
flash[:error] = 'Could not reset password'
end
redirect_to login_path
end
end
Name them differently and create two routes in config/routes.rb. If you really really want one action doing different things, which is not a great idea, check request.method or request.get?, request.post?, etc.
you can rename the actions in your controller
#get only
def get_forgot_password
end
#post only
def post_forgot_passord
end
and then on your routes.rb
match '/forgot_password' => 'pass_reset#get_forgot_password', :via => 'get'
match '/forgot_password' => 'pass_reset#post_forgot_password', :via => 'post'
the :via option do the trick.

Resources