How do I edit my Profile that is associated with User? - ruby-on-rails

I created the model User and the model Profile. On my homepage I have a link in the dropmenu navigation bar that links to Edit Profile. The problem I face is "No route matches {:action=>"edit", :controller=>"profiles", :id=>nil} missing required keys: [:id]".
The route for edit page is "edit_profile_path" with verb GET and URI pattern "/profiles/:id/edit(.:format)". I am having a hard time getting the "id" inserted. Below is the code that I have on my app.
In model Profile file I have:
class Profile < ActiveRecord::Base
belongs_to :user, dependent: :destroy
end
In model User file I have:
class User < ActiveRecord::Base
has_one :profile
end
The profile has many attributes, but one of them is "user_id" which is an integer that is equal to the User's id. So User #5 with id#5 is the owner of Profile#5.
Here is the code that I have in the View file:
<li><%= link_to "Edit Profile", edit_profile_path(#profile) %></li>
With regards to the code directly above, I have tried inserting different codes inside the parenthesis, from #profile.id, #profile, #user.id, and #user. But it has not worked.
I created a profiles controller and I think (but I am not certain) that my problem is coming from the profiles_controller file. Here is the code that I have:
class ProfilesController < ApplicationController
before_action :authenticate_user!
before_action :set_profile, only: [:edit, :update]
def edit
end
def new
#profile = Profile.new
end
def create
#profile = Profile.new(profile_params)
#profile.user_id = current_user.id
if #profile.save
redirect_to welcome_path
else
render 'new'
end
end
def update
#profile.update(profile_params)
redirect_to welcome_path
end
private
def set_profile
#profile = Profile.find(params[:id])
end
end

You are getting this error because in your view, your #profile in nil.
So, you have to get the current_profile in your view so that you can go to the edit page of that profile.
If you already have access to your current_user helper method, then, in your view, you can simply do:
<li><%= link_to "Edit Profile", edit_profile_path(current_user.profile) %></li>

A few things to note (which may be the key to solving your problem).
You are having a 1 to 1 relationship, and the user can access his profile only when he is logged in. Since you already have a (presumably properly working) current_user method, use it all the time.
def new
current_user.build_profile
end
def create
current_user.build_profile(profile_params)
#etc
end
It's also a logical way to get the user's profile
private
def set_profile
#profile = current_user.profile
end
In your view:
<%= link_to edit_profile_path(current_user.profile) %>
I think this makes much more sense in your code and is much more readable. Additionally, I think such approach will save you a lot of errors such as the one you're encountering now.

Have you tried?
edit_profile_path(id: #profile.id)
Also did you put this route in your routes file?

Related

Edit and update of user info. in RoR

I am using devise for user management so it let's user sign up with default email and password fields.
I added new fields/columns into the user model say username, designation and company.
So I have a profile view say with route '/users/1' and a link_to helper which would allow me to edit and update my user info.
By default i can only use users/edit route to edit my user info. How can i manage a new or separate edit and update option with different route say '/users/1/edit' from my profile view.
I read some posts before this but didn't help me. If anyone could outline things i should do. Thanks for reading :))
Edit:
routes file
root 'public#index'
devise_for :users
resources :users do
put 'users/:id/edit', to: 'users#edit'
end
user controller
class UsersController < ApplicationController
before_action :authenticate_user!
after_action :verify_authorized
before_action :set_user, only: %i[ show edit update ]
def index
#users = User.all
authorize User
end
def show
authorize #user
end
def edit
if current_user == #user
#user.update()
end
end
def update
authorize #user
if #user.update(secure_params)
redirect_to users_path, :notice => "User updated."
else
render 'edit'
end
end
private
def secure_params
params.require(:user).permit(:designation, :company,
:username)
end
def set_user
#user = User.find(params[:id])
end
end
In my view to go to edit:
<% if current_user.id == #user.id %>
<%= link_to 'Edit My profile', edit_user_path(#user), method: :edit,
class:"btn btn-primary" %>
<% end %>
If you really want to have a route user/:id/edit and not use the Devise default users/edit route(which edits the currently logged-in user). You can do the following:
Let's assume you have a users controller(if you don't have one, create one) and add an edit action to it which will handle the editing logic:
class UsersController < ApplicationController
# other code
def edit
user = User.find_by(id: params[:id]) # this id will be passed through the route
# Now here you need some authorization logic to prevent users from updating others.
# If you use CanCanCan, Pundit or any other authorization gem then write
# this logic there
if current_user == user
user.update() # do your update logic here with params you have
# render some json or whatever you want
else
# render some error messages in format you are using
end
end
end
This is the controller logic, now in your routes.rb file you need to register this route:
put 'user/:id/edit', to: 'users#edit'
This will edit the user with ID specified at :id.
Note again: This is not the approach I would take, I would rather just use the users/edit route and update the currently logged in user, but you wanted an example of this so do as you will

Not sure why strong params isn't working - param is missing or the value is empty:

hoping someone can help. I've been searching through other "param is missing" questions, but can't seem to figure out what's wrong.
In my routes file I have this nested resource "actions"
resources :jobs do
resources :actions
end
The associated models. Ignore "action_reference". That's something else.
class Job < ActiveRecord::Base
has_many :actions
end
class Action < ActiveRecord::Base
belongs_to :job
belongs_to :action_reference
end
And I'm trying to create a new action by making a POST request using button_to
Here's the ActionsController
class ActionsController < ApplicationController
before_action :set_job
before_action :set_action, only: [:show, :edit, :update]
# GET /jobs/:job_id/actions/:id
def show
end
# GET /jobs/:job_id/actions/new
def new
#action = Action.new
end
# GET /jobs/:job_id/actions/:id/edit
def edit
end
# POST /jobs/:job_id/actions/
def create
#action = #job.actions.create(action_params)
if #action.save
flash[:success] = "Next step successfully added."
redirect_to jobs_path
else
flash[:danger] = #action.errors.full_messages.join(", ")
redirect_to new_job_action_path
end
end
# PATCH to /jobs/:job_id/actions/:id
def update
if #action.update(action_params)
flash[:success] = "Next step successfully updated."
redirect_to jobs_path
else
flash[:danger] = #action.errors.full_messages.join(", ")
redirect_to edit_job_action_path
end
end
private
def set_job
#job = Job.find(params[:job_id])
end
def set_action
#action = Action.find(params[:id])
end
def action_params
params.require(:action).permit(:action_reference_id, :job_id, :completed_at, :next_action_date)
end
end
And here's my button_to
<%= button_to answer[:text], post_action_jobs_path(#job), method: "post", params: { action: { action_reference_id: answer[:action_reference_id], job_id: #job_id , completed_at: answer[:action_completed_at], next_action_date: answer[:next_action_date] } }, type: "button", class: "btn btn btn-info btn-block" %>
I know the problem has something to do with the arguments I'm passing to the post_action_jobs_path in the view or the ones I'm passing to action_params in the controller, but I can't figure it out.
When I run this I get the error:
undefined method `permit' for "create":String Did you mean? print
I saw some thread a little while ago saying something about "action" being a reserved word in Rails, so you have to use something else, but if that's true I'm not sure how to go about that.
Any help would be greatly appreciated :)
Yes unfortunately this is due to "action" being an existing method inside rails controllers. It is used to get the name of the action that has been called. In this case "action" will equal the string "create".
One thing you could do would be to rename you Action model to JobAction and use params.require(:job_action)
Sadly I couldn't seem to find away around this, so I renamed my "actions" table and replaced every reference to "action" with a different word "step". Now it works!

ActiveRecord::RecordNotFound in UsersController#destroy Couldn't find Item with 'id'=11

I am trying to create a simple app in Rails, where a user can list to-do items and delete them once completed. I'm having trouble with being able to destroy items. Each time I try this, the browser gives the following error:
ActiveRecord::RecordNotFound in UsersController#destroy Couldn't find Item with 'id'=11
I've tried various edits to the controller and _item partial.
Here are a couple links of some previous stack overflow questions/answers that I've tried to implement in order to fix this:
ActiveRecord::RecordNotFound - Couldn't find User without an ID
Couldn't find <Object> without an ID (Deleting a record)
I am using devise, Rails 5.0.0.1, and Ruby 2.3.1 (if that helps).
Here's my code:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def destroy
Item.find(params[:id]).destroy
end
end
class ItemsController < ApplicationController
def create
#item = current_user.items.new(items_param)
if #item.save
flash[:notice] = "Item was saved successfully."
redirect_to current_user
else
flash.now[:alert] = "Error creating item. Please try again."
render :new
end
end
def destroy
#item = Item.find(params[:id])
#item.destroy
end
private
def items_param
params.require(:item).permit(:name)
end
end
Here is the item partial _item.html.erb:
<%= content_tag :div, class: 'media', id: "item-#{item.id}" do %>
<%= link_to "", #item, method: :delete, class: 'glyphicon glyphicon-ok' %>
<%= item.name %>
<% end %>
Routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:show, :destroy] do
resources :items, only: [:create, :show, :destroy]
end
root 'users#show'
end
Browser Error:
ActiveRecord::RecordNotFound in UsersController#destroy Couldn't find Item with 'id'=11
What am I doing wrong?
Maybe this can help you:
Rails 2: Model.find(1) gives ActiveRecord error when id 1 does not exist
Basically: If the db raise an internal error tying to find the record, then Rails raise the error RecordNotFound. That does not means that the record doesn't exist, it means that Rails was not able to get it. maybe you need to look at your db
This record does not exist in your database, No user present with ID = 11
This is not any issue , its mistake and you can read this about rails guide and blogs
http://guides.rubyonrails.org/active_record_basics.html
http://api.rubyonrails.org/classes/ActiveRecord/RecordNotFound.html
Do
rails c
>> User.all # Write User.all it will give you all records from db
and in this way you can check the existing records in your users table
And correct you method destory in users_controller
def destroy
Item.find(params[:id]).destroy
end
It should be
def destroy
User.find(params[:id]).destroy
end

"Could not find User without ID" ActiveRecord Error and editing trouble

So I am having some trouble with my rails app and I think I went a little out of my own depth. I am creating a simple alumni application and I want users to be able to join organizations. For some reason in my new join page I get the error "Couldn't find User without an ID". I want to know why the ID isn't passing in, which would imply signed_in? = false. I don't know why everything worked find when I created other additions to my users controller but here it refuses to take on the logged in user id. I feel like I am missing something simple, let me know if updates are necessary!
Here is the relevant information in my Users controller:
class UsersController < ApplicationController
before_action :signed_in_user, only: [:edit, :update, :index, :show, :join]
before_action :correct_user, only: [:edit, :update, :join]
before_action :admin_user, only: :destroy
def join
end
def show
#user = User.find(params[:id])
#organization = #user.organization
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
...
private
def user_params
params.require(:user).permit(:name,:email, :password, :password_confirmation,:organization_id)
end
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
I included the def create method because I tried editing it to redirect users to the join page right after login but then I came across this error and I thought that was the problem so i switched it back. I guess it wasnt.... NOTE: I am basing a lot of this app off of the Hartl tutorial if that is helpful.
You should have a Memberships controller and model with a belongs_to :user (has_many :memberships for User & Organization), instead of defining a join method in the Users controller. The controller should be responsible for adding/deleting organization user-memberships. From that controller you fetch the user info by #user = User.find(:id) and don't forget to properly set the route file for nested resources.
resources :users do
resources :memberships
end
Also note that your join method doesn't create any instance variables for the view (#user). It looks like it properly goes through the signed_in_user action but nothing is instantiated in the join method.
Change line 3 to:
before_action :correct_user, only: [:edit, :update]
If the purpose of "join" is to create a user, then there should not be a user yet. However if your purpose for "join" is to get the current user you should add this to your join method:
#user = current_user
What about if you changed it to this:
def show
#users = User.all
#user = #users.find(params[:id])
#organization = #user.organization
end

How can I make an link to an action?

At the time I have two models: Patient (has many), and Treatment (belongs to).
Until now I displayed the form for a new treatment on the patient show page and all worked fine. But now i want to outsource the treatments form to an new page. To visualize it better:
<%= render "treatments/form" %>
change to:
<% link_to "new", "treatments/form" %>
SO my problem is that I always become an route error:
No route matches [GET] "/patients/treatments/form"
But the routes look so, and i thought they would work:
resources :patients do
resources :treatments
resources :paintings
end
And the controller of the treatments:
class TreatmentsController < ApplicationController
def create
#patient = Patient.find(params[:patient_id])
#treatment = #patient.treatments.create(params[:treatment])
redirect_to patient_path(#patient)
end
def destroy
#patient = Patient.find(params[:patient_id])
#treatment = #patient.treatments.find(params[:id])
#treatment.destroy
redirect_to patient_path(#patient)
end
end
Since your proposed form is really just a way of creating a new patient treatment, you should consider following RESTful conventions and create a new TreatmentsController action called new:
# app/controllers/treatments_controller.rb
class TreatmentsController < ApplicationController
def new
#patient = Patient.find(params[:patient_id])
end
Since your treatments routes are a nested resource of the patients nested resource routes, you'll need to pass the patient_id to your link helper:
<%= link_to "New Patient Treatment", new_patient_treatment_path(#patient) %>
This will enable you to properly access your nested route for treatment#new.

Resources