Rails ActiveAdmin: ActiveRecord::RecordNotFound in Admin::UsersController#show - ruby-on-rails

I want to create button to change User status:string from inactive to active inside active admin show action. To do so I'm using collection_action with below code:
ActiveAdmin.register User do
permit_params :email, :password, :password_confirmation, :status
collection_action :update_status, method: :post do
user.update!(status: 'active')
redirect_to user_path, notice: 'User status updated'
end
Then I render custom partial _show.html.erb
<tr>
<td colspan='2'>
<% if #user.status == 'inactive' %>
<%= link_to 'Activate user', update_status_admin_users_path %>
<% end %>
</td>
Here is what ActiveAdmin generated dynamically by collection_action
bin/rails routes
update_status_admin_users POST /admin/users/update_status(.:format) admin/users#update_status
Instead of updating the data I'm getting an error:
ActiveRecord::RecordNotFound in Admin::UsersController#show
Couldn't find User with 'id'=update_status

Above error is because you are redirecting to user_path for which id parameter it require to redirect, and as you are using collection_action id parameter is missing.
If your intention is to update just one user, then use member_action instead of collection_action.
using resource
member_action : update_status, method: :put do
resource.update!(status: 'active')
redirect_to user_path, notice: 'User status updated'
end
with own finder
member_action : update_status, method: :put do
user = User.find(params[:id])
user.update!(status: 'active')
redirect_to user_path, notice: 'User status updated'
end
<td colspan='2'>
<% if #user.status == 'inactive' %>
<%= link_to 'Activate user', update_status_admin_user_path, method: :put %>
<% end %>
</td>

Related

Add checkbox to edit bool value of user in devise in Rails

I have created a user using devise gem. I have added a column admin to the User table which has boolean value. Now what I need is to add checkboxes after every user in users_page and give a feature so that when the checkbox is checked the value of admin column changes to true. How can I add the functionality?
users_controller.rb
class UsersController < ApplicationController
def users_page
#users = User.all
end
def change_user_role
#user = User.find(params[:id])
format.html { redirect_to users, notice: 'Role changed successfully' }
end
def destroy
#user = User.find(params[:id])
#user.destroy
if #user.destroy
redirect_to root_url, notice: "User deleted."
end
end
end
users_page.html.erb
<h1>Users</h1>
<% #users.each do |user| %>
<h5><%= user.email %></h5>
<%= user.admin %>
<%= form_tag({controller: "users", action: "change_user_role"}, method: "get") do %>
<%= check_box_tag(:admin, checked: false) %>
<p><%= submit_tag 'Submit Answer' %></p>
<% end %>
<br>
<%= link_to "Destroy", admin_destroy_user_path(user), method: :delete, data: { confirm: "You sure?" } %>
<% end %>
routes.rb
Rails.application.routes.draw do
root to: 'pages#home'
get 'users/users_page'
devise_for :users
match 'users/:id' => 'users#destroy', :via => :delete, :as => :admin_destroy_user
get 'users#change_user_role'
end
Here I should submit the value of the checkbox in users_page to change_user_role and update the value in db and redirect it to users_page. How can I do that?
First of all, change your get method to put in your routes.rb because you'll be updating the resource in database:
Rails.application.routes.draw do
root to: 'pages#home'
get 'users/users_page'
devise_for :users
match 'users/:id' => 'users#destroy', :via => :delete, :as => :admin_destroy_user
// it will require user id in your url
resources :users do
member do
put :change_user_role
end
end
end
More on routes here
Then change your view to something like this:
<h1>Users</h1>
<% #users.each do |user| %>
<h5><%= user.email %></h5>
<%= form_for(user, url: change_user_role_user_path(user)) do |f| %>
<%= f.check_box(:admin) %>
<p><%= f.submit 'Submit Answer' %></p>
<% end %>
<br>
<%= link_to "Destroy", admin_destroy_user_path(user), method: :delete, data: { confirm: "You sure?" } %>
<% end %>
More on forms here
Your controller should look something like this:
class UsersController < ApplicationController
def users_page
#users = User.all
end
def change_user_role
#user = User.find(params[:id])
// if user is updated successfully then redirect
if(#user.update_attributes(user_params)
format.html { redirect_to users, notice: 'Role changed successfully' }
end
end
def destroy
#user = User.find(params[:id])
if #user.destroy
redirect_to root_url, notice: "User deleted."
end
end
// new method added to allow specific attributes only and discarding other malicious attributes that user may send
def user_params
params.require(:user).permit(:admin)
end
end
More on parameters here

How to set "approved" user attribute to true with a button in Rails

I have a user model established by Devise and it has a Boolean attribute "approved" with default value set to false.
I created a separate controller called "newcomers" where I set index action to display all not approved users and update action to set "approved" to true
class NewcomersController < ApplicationController
def index
#users = User.where("approved = ?", false)
end
def update
#user = User.find(params[:id])
#user.update_attribute :approved, true
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
end
So, in my view I did
<h1>Members Requests</h1>
<% #users.each do |user| %>
<%= user.email %>
<%= form_for user, url: newcomers_path, method: :patch do |f| %>
<%= f.submit "Approve" %>
<% end %>
<% end %>
and in my routes I have resources :newcomers
So, I do not know how to make the button work the way it should. Meaning it should just update the attribute "approved" and set it to true. and return to the same page (index)
Try following code
<h1>Members Requests</h1>
<% #users.each do |user| %>
<%= user.email %>
<% if user.approved %>
<%= link_to 'Unapprove', newcomer_path(user, approve: false), method: :put %>
<% else %>
<%= link_to 'Approve', newcomer_path(user, approve: true ), method: :put %>
<% end %>
controller
def update
#user = User.find(params[:id])
#user.update_attribute :approved, params[:approve]
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
Just use a link_to in your view an point it to the update action in your controller:
<%= link_to 'Approve', newcomer_path(user_id), method: :put %>
In your controller just update the user with the given id an redirect to index path as you already do.
If you want it somewhat more fancy you can add a remote: true to your link_to and respond with an js to delete only the affected row from your view.
Make below changes
In view
<%= form_for user, url: newcomer_path(user, approved: true), method: :patch do |f| %>
<%= f.submit "Approve" %>
<% end %>
and in controller
def update
if params[:user].nil?
#user = User.find(params[:id])
#user.update_attribute :approved, true
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
end
let me know if it is not working...

Using Ajax requests in rails

Hi I want to build an app using Ajax. Whenever a user visits an other user page he can add him as a friend by clicking add friend link. This is my current code in users/show page
<% if current_user.friend?(current_user,#user) %>
<%= link_to "Unfriend", relation_path(#relation), user: #user, method: :delete, data: { confirm: 'Are you sure? This action cannot be undone' }, class: 'btn btn-default' %>
<% elsif #user != current_user %>
<%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post, class: 'btn btn-default' %>
<% end %>
My code in relations controller
def create
if params[:friend_id]
if Relation.where(user_id: current_user.id, friend_id: params[:friend_id]).present?
redirect_to user_path(params[:friend_id]), notice: "Already friends"
elsif current_user.id == params[:friend_id]
redirect_to user_path(params[:friend_id]), alert: "Invalid Request"
else
#relation = current_user.relations.new(friend_id: params[:friend_id], subject: Constants::Subject::MAKE)
if #relation.save
friend = User.find(params[:friend_id])
friend.relations.create!(friend_id: current_user.id, subject: Constants::Subject::MAKE)
redirect_to user_path(params[:friend_id]), notice: "Added as friend"
else
redirect_to user_path(params[:friend_id]), alert: "Could not add as friend"
end
end
else
redirect_to current_user, notice: "Invalid Request"
end
end
I am following this Ryan Bates rails casts. How can I make the link_to add friend Ajax request instead of html request. The current code is working fine. I want to add Ajax functionality for this. I have seen a lot of questions but I could not understand what exactly to be done. Please help.
Add remote: true to the link_to tag. There is more information in the guides abou rails and ajax. You will need a respond_to block to handle the response.
Start with adding remote: true and use the console to see the call being made and what the response is. Then you can figure out how to handle the response.
<%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post, remote: true, class: 'btn btn-default' %>
Please take a look:
Move your buttons into a partial
Render it inside a div with ID = "actions"
Update your controller response with format js
Add field create.js.erb which render your buttons by javascript
Render your flashes box by javascript by the same way (if needed)
your view_file.erb
<div id="actions">
<%= render "views/realtions/actions", relation: #relation, friend: #user %>
</div>
views/realtions/_actions.html.erb
<% if current_user.friend?(current_user, friend) %>
<%= link_to "Unfriend", relation_path(relation), user: friend, method: :delete, remote: true, data: { confirm: 'Are you sure? This action cannot be undone' }, class: 'btn btn-default' %>
<% elsif friend != current_user %>
<%= link_to "Add Friend", friendships_path(friend_id: friend.id), method: :post, remote: true, class: 'btn btn-default' %>
<% end %>
views/realtions/create.js.erb
<%- if #friend.present? %>
$("#actions").html("<%= j render 'views/realtions/actions', relation: #relation, friend: #friend %>")
<%- end %>
// render your flashes to DOM here!
controllers/relations_controller.rb
def create
if params[:friend_id]
#friend = User.find(params[:friend_id])
if Relation.where(user_id: current_user.id, friend_id: #friend.id).present?
flash[:notice] = "Already friends"
elsif current_user.id == params[:friend_id]
flash[:error] = "Invalid Request"
else
#relation = current_user.relations.new(friend_id: params[:friend_id], subject: Constants::Subject::MAKE)
if #relation.save
#friend.relations.create!(friend_id: current_user.id, subject: Constants::Subject::MAKE)
flash[:notice] = "Added as friend"
else
flash[:error] = "Could not add as friend"
end
end
else
flash[:notice] = "Invalid Request"
end
respond_to do |format|
format.js
end
end
Hope this help

Rails: Favorite Model working but favorite/unfavorite links not working

I followed the steps from the first answer posted by Thomas here
I can go into Heroku Console and manually favorite phootos by users so the models are setup correctly and working but my favorite/unfavorite links are not working.
<p><strong>Picture:</strong></p>
<%= image_tag(#phooto.picture) %>
<%= link_to("< Previous", #phooto.previous) if #phooto.previous %>
<%= link_to("Next >", #phooto.next) if #phooto.next %>
<% if current_user %>
<%= link_to "favorite", favorite_phooto_path(#phooto, type: "favorite"), method: :put %>
<%= link_to "unfavorite", favorite_phooto_path(#phooto, type: "unfavorite"), method: :put %>
<% end %>
Heroku Log
Started PUT "/phootos/24/favorite?type=favorite"
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.6ms)
ActiveRecord::AssociationTypeMismatch (Phooto(#70057240967940) expected, got NilClass(#70057199933300)):
app/controllers/phootos_controller.rb:29:in `favorite
PhootosController
def show
#phooto = Phooto.find(params[:id])
end
def favorite
type = params[:type]
if type == "favorite"
**rb.29** current_user.favorites << #phooto
redirect_to :back, notice: 'You successfully favorited #{#phooto.name}'
elsif type == "unfavorite"
current_user.favorites.delete(#phooto)
redirect_to :back, notice: 'You successfully unfavorited #{#phooto.name}'
else
redirect_to :back, notice: 'Nothing happened.'
end
end
Phootos/show.html.erb
<p><strong>Picture:</strong></p>
<%= image_tag(#phooto.picture) %>
<%= link_to("< Previous", #phooto.previous) if #phooto.previous %>
<%= link_to("Next >", #phooto.next) if #phooto.next %>
<% if current_user %>
<%= link_to "favorite", favorite_phooto_path(#phooto, type: "favorite"), method: :put %>
<%= link_to "unfavorite", favorite_phooto_path(#phooto, type: "unfavorite"), method: :put %>
<% end %>
routes.rb
resources :users
resources :phootos
resources :phootos do
put :favorite, on: :member
end
Honestly, a better pattern for this will be to match the favorite route based on its HTTP verb:
#config/routes.rb
resources :users
resources :phootos do
match :favorite, on: :member, via: [:put, :delete]
end
This will do away with the type argument in your path (which is causing issues):
<% if current_user %>
<%= link_to "favorite", favorite_phooto_path(#phooto), method: :put %>
<%= link_to "unfavorite", favorite_phooto_path(#phooto), method: :delete %>
<% end %>
You'll have to change your controller to handle the requests & variable:
def favorite
#phooto = Phooto.find params[:id]
if request.put?
current_user.favorites << #phooto
redirect_to :back, notice: 'You successfully favorited #{#phooto.name}'
elsif request.delete?
current_user.favorites.delete(#phooto)
redirect_to :back, notice: 'You successfully unfavorited #{#phooto.name}'
else
redirect_to :back, notice: 'Nothing happened.'
end
end
Just add this line as your first line in your favorite method in PhootosController
#phooto = Phooto.find(params[:id])

Favorites model for my rails app

I have a user and guideline model.
I would like a user to be able to mark a guideline as their favourite and then view a list of all their favourite guidelines.
It's not quite right. I'm not sure if the 'favourite' action is adding a favourite correctly; or if it is adding correctly it's not displaying correctly in the favourites view (so 'show' action may not be right)...
*CONTROLLER*guidelines_controller.rb
def favourite
type = params[:type]
if type == "favourite"
#guideline= Guideline.find_all_by_id(params[:guideline_id])
current_user.favourite_guidelines << #guideline
redirect_to :back, notice: 'You favourited #{#guideline.name}'
elsif type == "unfavourite"
current_user.favourite_guidelines.delete(#guideline)
redirect_to :back, notice: 'Unfavourited #{#guideline.name}'
else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end
*CONTROLLER*favourites_controller.rb
def show
#user = User.find_by_profile_name(params[:id])
if #user
#guidelines = #user.favourite_guidelines.all
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
end
*ROUTES*routes.rb
get "guidelines/favourite"
get "favourites/show"
*MODEL*user.rb
has_many :guidelines
has_many :favourite_guidelines
*MODEL*favourite_guidelines.rb
attr_accessible :guideline_id, :user_id
belongs_to :user
*VIEWS*guidelines/index.html.erb
<% if current_user %>
<%= link_to "favourite", guidelines_favourite_path(guideline, type: "favourite"), method: "get" %>
<%= link_to "unfavourite", guidelines_favourite_path(guideline, type: "unfavourite"), method: "get" %>
*VIEWS*favourites/show.html.erb
<% if #guidelines %>
<% #guidelines.each do |guideline| %>
<div class="well">
<%= link_to guideline.title, guideline %>
<br />
<%= guideline.content %>
<br />
Added <%= time_ago_in_words(guideline.created_at) %> ago
</div>
<% end %>
<% end %>
As per your comment following returns nil:
#guideline= Guideline.find_by_id(params[:guideline_id]) #=> nil
current_user.favourite_guidelines << nil #Gives association mismatch error
I think params[:guideline_id] is nil. Post your params from log file.
Or try this:
Change your link to like this:
<%= link_to "favourite", guidelines_favourite_path(guideline_id: guideline.id, type: "favourite"), method: "get" %>
<%= link_to "unfavourite", guidelines_favourite_path(guideline_id: guideline.id, type: "unfavourite"), method: "get" %>
In your earlier case:
#guideline= Guideline.find_all_by_id(params[:guideline_id]) #=> []
current_user.favourite_guidelines << [] #=> Valid and inserting nothing

Resources