Override edit functionality Devise, rails - ruby-on-rails

I was trying to override devise default edit method. Normally, by default, it can only edit current_user. But I want to edit any user I want. That's why I coded like this:
IN CONTROLLER:
def edit
#user = User.find(params[:id])
end
And it is called from the show, where I called this function like this:
SHOW.HTML.ERB:
<%= link_to user_profiles_edit_path(#user.id) do%>
<button class="btn btn-info">Edit Profile</button>
<% end %>
And in edit, I had a form, which starts like this:
EDIT.HTML.ERB:
<%= form_for(#user) do |f| %>
<table class="table table-striped">
<tr>
<th>First Name</th>
<td><%= f.text_field(:first_name, :class=>"full-width-input") %></td>
</tr>
<tr>
<th>Last Name</th>
<td><%= f.text_field(:last_name, :class=>"full-width-input") %></td>
</tr>
...
...
...
And I added this line in my routes.rb:
ROUTES.RB
get "/users/:id/edit/" => "users/registrations#edit",:as =>"user_profiles_edit"
But, After doing all these, I am getting this error:
undefined method `user_path' for #<#<Class:0x007f3da064c050>:0x007f3da065adf8>
Did you mean? users_path

Related

How do I delete a table row as well as the corresponding array element in the controller for Ruby on Rails?

I am displaying table records from an array in a view, but have added delete and edit buttons to each row, in which I want to be able to delete the dynamically instantiated table row when the delete button is pressed, as well as the array item from the array that populated it. I want the page to refresh as well.
Past attempts:
I have tried creating forms with submit_tags for deleting, but to no avail, as well as routing and creating destroy and delete functions. I have looked up solutions to this for hours but none worked for me.
I am a beginner at Ruby. The code is a bit untidy due to me having inserted solutions, trying to test them, and then deleting.
CODE:
I have created an array in my controller called #db_data, where a search button only displays specific elements with #hospital_data:
class HospitalsController < ApplicationController
def index
#ONLY CHANGE THIS TO DATABASE DATA IN 3D ARRAY FORMAT!!
#db_data=[["1","Helen Joseph"],["2","Bara"],["3","Charlotte Maxeke"]]
#Format is [[hospital ID], [hospital name]]
#SEARCH BAR CODE
#DON'T CHANGE BELOW CODE!!==========================
#data = params[:searchHospitals]
if #data.blank?
#hospitals_array=#db_data
else
#hospitals_array=#db_data.select{|x,y| y.match(/#{#data}/) }
end
#===================================================
end
end
The html.erb file just for the display table is as follows:
<!--TABLE-->
<div class="m-4">
<table id="cartTable" class="table">
<thead>
<tr>
<th scope="col">Hospital ID</th>
<th scope="col">Hospital Name</th>
</tr>
</thead>
<tbody>
<!--loop through each item in hospital array-->
<% #hospitals_array.each_with_index do |hosp_element, index| %>
<tr>
<th scope="row" class="col-5" > <%= hosp_element.first %> </th>
<td class="col-6"><%= hosp_element.last %> </td>
<!--edit and delete functionality-->
<td class="col-1">
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-outline-dark" >Edit</button>
<button type="button" class="btn btn-outline-dark" >Delete</button>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
My route for this is currently:
get "/hospitals",to: "hospitals#index"
Well I am not sure if I understand your problem in 100% but I guess you want to add edit and delete buttons to your view.
To delete your rows we have to add few things, at first let's update routes.rb file:
# For explanation I recommend: https://guides.rubyonrails.org/routing.html
resources :hospitals, only: [:index, :destroy]
then we need to define controller actions for our new routes, I've also refactored your Index action to use ActiveRecord:
class HospitalsController < ApplicationController
def index
#hospitals = Hospital.select(:id, :name)
if params[:searchHospitals]
# It's better to use DB engine for optimization instead of Ruby `.select`
#hospitals = #hospitals.where("NAME like '%#{params[:searchHospitals]%'")
end
end
def destroy
#hospital = Hospital.find(params[:id])
#hospital.destroy
redirect_to(hospitals_path)
end
end
and finally in the view
<% #hospitals.eachx do |hospital| %>
<tr>
<th scope="row" class="col-5" > <%= hospital.id %> </th>
<td class="col-6"><%= hospital.name %> </td>
<td class="col-1"><%= link_to 'Destroy', micropost, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-outline-dark' %></td>
</tr>
<% end %>
For edit button you'll have to create another methods in controller and add additional views.

Active record is not display table

As working on the Active Record as i have work on different function for active reocrd like Avg, sum and count as it display working fine and also Chart,
but one things is baffle me and i still cannot get it working and it should be working fine, as i cannot get display all data list table like
<table id="dttb" class="table table-hover">
<thead>
<tr>
<th> full name </th>
</tr>
</thead>
<tbody>
<tbody>
<% #user.each do |user| %>
<tr>
<td><%= user.fullname %></td>
</tr>
<% end %>
</tbody>
</tbody>
</table>
as it should be working as the error is kept displayed
undefined method `each' for nil:NilClass
as I look up information and most of them are mention .each do, seems I am doing wrong as I have used
<%= User.count(:user) %>
and
<%= column_chart User.group(:provider).count(:user) %>
and it seems working fine as query function.
so I tried again with find_each
<% User.find_each do |user| %>
<tr>
<td><%= puts user.fullname %></td>
</tr>
<% end %>
and the error is gone but it does not display at the data and it's show blanks unless I put 'link_to' but they keep display like
and I have put on AdminController.rb
class AdminController < ApplicationController
before_action :authenticate_user!
def index
#user = User.all
#tools = Tool.all
end
end
seems I miss something, I have look google or stackover flow, most of them answer are very same as this code as I wrote
Update: as I am able to get some data like a phone number or email
Here is code i wrote
<% User.find_each do |user| %>
<tr>
<td><%= link_to user.id, user %></td>
<td><%= link_to user.email, user %></td>
<td><%= link_to user.created_at.strftime('%v'), user %></td>
<td><%= link_to user.fullname, user %></td>
<td><%= link_to user.phone_number, user %></td>
</tr>
<% end %>
but frustration with fullname as it should be displayed but it not
Set #user (or better #users) in the controller:
def index # or the actual action name
#users = User.all # or User.order(:fullname)
end

Controller fails to pass instance variables into view

In my home page I iterate over collections of objects, and for each object I render its attributes in a table row. There are four collections of objects, defined as instance variables in my controller, all making Guard (according to the used method) raising one of the following errors:
ActionView::Template::Error: undefined method `each_with_index' for nil:NilClass
ActionView::Template::Error: undefined method `any?' for nil:NilClass
The code in my application view raising the above errors is:
<table class="col-md-4 col-md-offset-1">
<thead>
<tr>
<th> Rank </th>
<th> Gamer </th>
<th> Points </th>
</tr>
</thead>
<tbody>
<% #atp_gamers.each_with_index do |gamer, index| %>
<tr>
<td class="index"> <%= index+1 %> </td>
<td class="gamer"> <%= gamer.name %> </td>
<td class="atppoints"> <%= gamer.atpscore %> </td>
</tr>
<% end %>
<tr class="current-user">
<td> <%= #atp_gamers.to_a.index(current_user) + 1 %> </td>
<td> <%= current_user.name %> </td>
<td> <%= current_user.atpscore %> </td>
</tr>
</tbody>
</table>
<table class="col-md-4 col-md-offset-2">
<thead>
<tr>
<th> Year </th>
<th> Champion </th>
<th> Points </th>
</tr>
</thead>
<tbody>
<% if #atp_champions.any? %>
<% #atp_champions.each do |champion| %>
<tr>
<td class="year"> <%= champion.created_at.year %> </td>
<td class="winnername"> <%= champion.name %> </td>
<td class="winnerpoints"> <%= champion.points %> </td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
The above code is part of a partial (named _gamers_home.html.erb) rendered in the original home page:
<% if logged_in? %>
<% if current_user.gamer? %>
<%= render 'static_pages/gamers_home' %>
<% else %>
<%= render 'static_pages/non_gamers_home' %>
<% end %>
<% else %>
<%= render 'static_pages/non_logged_in_home' %>
<% end %>
The logged_in? method is defined as !current_user.nil?
The instance variables that result nil are: #atp_gamers, #wta_gamers, #atp_champions and #wta_champions, defined in the controller as follows:
def home
if logged_in? && !current_user.gamer?
...l
elsif logged_in? && current_user.gamer?
#gamers = User.where(gamer: true)
#atp_gamers = #gamers.order(atpscore: :desc).limit(50)
#wta_gamers = #gamers.order(wtascore: :desc).limit(50)
#atp_champions = AtpChampion.all
#wta_champions = WtaChampion.all
...
end
end
The first instance variable raising the error (each_with_index' for nil:NilClass) is #atp_gamers. In view I tried to change it with its explicit value, that is User.where(gamer: true).order(atpscore: :desc).limit(50), and the respective code is accepted. After this change, Guard raises an error for #atp_champions.
With rails console #atp_gamers and #wta_gamers are not empty, returning 50 records out of 100 users. #atp_champions and #wta_champions are not nil, but empty arrays.
I suspect that this might be an issue raised only by Guard, because the rails server succeeds in rendering the view.
def home
if logged_in? # delete this line
...
end # delete this line
end
Delete the if logged_in?, and see what happens.
Maybe you have to use before_action :logged_in_user, only :home in controller and define the logged_in_user method as private method.
If non-logged-in users also allowed to access the home action, you need to use if statement erb in the view. Like,
<% if logged_in? %>
<% #atp_gamers.each_with_index do |gamer, index| %>
...
<% end %>
--UPDATE--
Maybe, it needs to toss variables to the partial.
Replace
<%= render 'static_pages/gamers_home' %>
to
<%= render partial: 'static_pages/gamers_home', locals: {atg_gamers: #atp_gamers, wta_gamers: #wta_gamers, atp_champions: #atp_champions, wta_champions, #wta_champions} %>
and, replace the #atp_gamers, #wta_gamers, #atp_champions, #wta_champions in the partial to atp_gamers, wta_gamers, atp_champions, wta_champions.
Try and see what happens.

Pass data from index method of one controller to create of another

I generated a devise model User, and I also have a Conversation controller. I'm showing all users, except the logged in one, and I'm trying to create a new Conversation between user1 and user2, but I get redirected to the index method of the Conversation Controller, not the create one. I understood from this link that making a post from one controller to another is a bad idea Rails: How to POST internally to another controller action?.
I've also tried to make a send_message method inside the Users controller and define it as a post in routes, but I get redirected to the show method of the Users controller.
What is the clean way of doing this?
class UsersController < ApplicationController
before_action :authenticate_user!
def index
#users = User.where.not(id: current_user.id)
end
def send_message
# #conversation = Conversation.new(conversation_params)
# if #conversation.save
#
# end
end
end
index.html.erb
<div class="col-xs-12 col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1> User's index </h1>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Email</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.email %></td>
<td><%= time_ago_in_words(user.created_at) %> ago</td>
<td>
<div class="btn-group">
<%= link_to 'Send', conversations_path(sender_id: current_user.id, recipient_id: user.id) %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
Edit:
private
def conversation_params
params.require(:conversation).permit(:sender_id, :recipient_id)
end
<ActionController::Parameters {"_method"=>"post", "authenticity_token"=>"394MDmcVVelccU//8ISYeqmk146exYc6G7SrrAhbCA/yQ/K8KTpSn/0EkXlZ4hB/g==", "recipient_id"=>"1", "sender_id"=>"3", "controller"=>"conversations", "action"=>"create"} permitted: false>
By default link_to helper sends GET request. You can do it with adding method: :post to its options.
<%= link_to 'Send', path, method: :post %>
You could redirect to new_converstion_path instead of conversations_path. And link by default sends GET not POST request.

devise admin user approval setup

Seems like the tutorial located here has a couple omissions:
When creating the admin accessible controller method, they don't specify which custom devise controller to use, or which base controller to inherit from. So I've placed my code in a PagesController:
class PagesController < ApplicationController
def approve_users
if current_user.admin?
if params[:approved] == "false"
#users = User.find_by_approved(false)
else
#users = User.all
end
end
end
end
The view code that allows you to switch between all users and all unapproved users results in a NoMethodError in Pages#approve_users: undefined method 'each' for User whenever you select to show the users for whom :approved => false. I know why noMethodErrors spring up in app development, and would normally be able to wrap my head around why I'm getting this error. It works when #users = User.all, but not when #users = User.find_by_approved(false)
<% if current_user.admin? %>
<h2>Users</h2>
<%= link_to "All Users", :action => "approve_users" %> | <%= link_to "Users awaiting approval", :action => "approve_users", :approved => "false" %>
<div class="ui form">
<table>
<thead>
<tr scope="col">
<th>First name</th>
<th>Last name</th>
<th>E-mail</th>
<th>Approve</th>
</tr>
</thead>
<% #users.each do |user| %>
<tbody>
<tr>
<td><%= user.firstname %></td>
<td><%= user.lastname %></td>
<td><%= user.email %></td>
<td class="ui checkbox">
<input type="checkbox" tabindex="0" class="hidden">
</td>
</tr>
</tbody>
<% end %>
</table>
</div>
<% end %>
The wiki says it that it provides a simple way to approve users, but their view code actually just provides a simple way to list all users. I'm assuming that I need to use a form helper.
I made a custom admin controller specifically for an admin control panel and put all of the tools in an index page. You can probably do it a number of ways, though.
The common consensus on this seems to be that if you switch #users = User.find_by_approved(false) to #users = User.where(approved: false), it works better. That's what I currently have and it works very well.
I had this problem as well, and I ended up scrapping devise and making a custom user sign in method. You should be able to make it work, though. I followed the tutorial here and it helped immensely. Basically, you want to create a method which will approve users in your admin controller. This is the one I used:
`
def approve
User.where(id: params[:user_id]).update_all(approved: true)
redirect_to admin_index_path
end
From there, you add a put method to your routes.
put 'approve_admin', to: "admin#approve", as: :approve_admin
Finally, wrap your list of users in a form tag and add a hash of all of the user IDs you want to update as a hash.
<%= form_tag(approve_admin_path, method: :put) do %>
<% for user in #unapproved_users %>
<tr>
<td class="mdl-data-table__cell--non-numeric"><%= check_box_tag "user_id[]", user.id %></td>
<td><%= user.name %></td>
<td><%= user.email %></td>
</tr>
<% end %>
</tbody>
</table>
<%= submit_tag "Mark as approved", class: 'mdl-button mdl-js-button mdl-button--raised approve' %>
<% end %>
I made a method for approving users and another for unapproving users so I switched up the #users.each iteration in favor of a for iteration. I added #unapproved_users to my index method to make this work properly. Hope this works for you!

Resources