I have created a destroy action for my user profile picture. The destroy action works properly and the photo is deleted. I can add another picture without any problem, but when I try to delete the picture again I receive the following error message:
Couldn't find Avatar with 'id'=1
This is what is stored in my database Avatar.all reads:
[#<Avatar id: 2, avatarpic: "cat_astronaut.jpg", user_id: 1, created_at: "2017-12-05 17:02:08", updated_at: "2017-12-05 17:02:08">]
The id is at 2 and not 1, even though I successfully deleted the first picture with an id of 1. Every time I delete a picture and upload a new one, the id is incremented. So when I try to delete the second uploaded picture, it can't find the right id. I need the id to be reset to 1 every time I delete the picture.
Controller is as follows:
class AvatarsController < ApplicationController
def create
#user = User.find(params[:user_id])
#avatar = Avatar.new(avatar_params)
#avatar.user = #user
#avatar.save
# Three lines above can be replaced with
# #user.create_avatar(params)
redirect_to user_path(#user)
end
def destroy
#user = User.find(params[:user_id])
#avatar = Avatar.find(params[:id])
#avatar.user = #user
#avatar.destroy
redirect_to user_path(#user)
end
private
def avatar_params
params.require(:avatar).permit(:avatarpic)
end
end
There is only 1 photo according to my user model:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :places
has_many :comments, dependent: :destroy
has_one :avatar, dependent: :destroy
end
Code for User's view profile page:
<%= link_to user_avatar_path(#user), :title => "Upload New Photo", method: :delete, data: { confirm: 'Are you sure you want to change your Photo?' } do %>
<%= image_tag #user.avatar.avatarpic %>
<% end %>
rake routes:
root GET / places#index
place_comments POST /places/:place_id/comments(.:format) comments#create
place_photos POST /places/:place_id/photos(.:format) photos#create
places GET /places(.:format) places#index
POST /places(.:format) places#create
new_place GET /places/new(.:format) places#new
edit_place GET /places/:id/edit(.:format) places#edit
place GET /places/:id(.:format) places#show
PATCH /places/:id(.:format) places#update
PUT /places/:id(.:format) places#update
DELETE /places/:id(.:format) places#destroy
user_avatars POST /users/:user_id/avatars(.:format) avatars#create
user_avatar DELETE /users/:user_id/avatars/:id(.:format) avatars#destroy
user GET /users/:id(.:format) users#show
routes.rb:
Rails.application.routes.draw do
devise_for :users
root 'places#index'
resources :places do
resources :comments, only: :create
resources :photos, only: :create
end
resources :users, only: [:show] do
resources :avatars, only: [:create]
resources :avatars, only: [:destroy]
# or resources :avatars, only: [:create, :destroy]
end
end
Avatar Model:
class Avatar < ApplicationRecord
belongs_to :user
mount_uploader :avatarpic, AvatarUploader
end
Thank you for your help.
Your link_to is missing the avatar_id. Change
user_avatar_path(#user)
To
user_avatar_path(#user, #user.avatar)
Related
I’m trying to create a delete function for images that has been uploaded via active storage in my rails app.
I’m using devise for sign up, wicked wizard for multi step and cancancan for authorization. I'm also using rails admin.
But I get this error, and I can’t figure out how to make it work. I can see it has something to do with the routes, but i don't understand what the problem is and how to fix it. Any help would be much appreciated.
my form
<%= form_for #user, url: wizard_path, method: :put do |f| %>
<% if #user.clinic_images.attached? %>
<% #user.clinic_images.each do |image| %>
<%= image_tag(image.variant(resize: "100x100")) %>
<%= link_to ‘Delete this image’, delete_image_attachment_registration_url(image.signed_id),
method: :delete,
data: { confirm: ‘Are you sure?’ } %>
<% end %>
<% end %>
<% end %>
Routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users, controllers: {:registrations => "users/registrations"}
resources :registration_steps
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root 'pages#index'
get 'about', to: 'pages#about'
get 'team', to: 'pages#team'
get 'faqs', to: 'pages#faqs'
get 'faqspractitioners', to: 'pages#faqspractitioners'
get 'faqsusers', to: 'pages#faqsusers'
get 'login', to: 'pages#login'
get 'signup', to: 'pages#signup'
get 'search', to: 'pages#search'
devise_scope :users do
resources :registrations do
member do
delete :delete_image_attachment
end
end
end
end
registrations_controller.rb
# frozen_string_literal: true
class Users::RegistrationsController < Devise::RegistrationsController
def delete_image_attachment
#image = ActiveStorage::Blob.find_signed(params[:id])
#image.purge_later
redirect_to root_path
end
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
# GET /resource/sign_up
# def new
# super
# end
# POST /resource
# def create
# super
# end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
protected
# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_up_params
# devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
# end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
def after_sign_up_path_for(resource)
registration_steps_path
end
def after_update_path_for(resource)
registration_steps_path
end
# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
end
user.rb
class User < ApplicationRecord
def current_step?(step_key) current_step == step_key end
enum gender: { Mand: 0, Kvinde: 1 }
def self.genders_for_select
genders.keys.map{ |x| [x.humanize, x] }
end
has_one_attached :clinic_logo
has_one_attached :practitioner_image
has_many_attached :clinic_images
# Note that implicit association has a plural form in this case
scope :with_eager_loaded_images, -> { eager_load(images_attachments: :blob) }
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
after_create :send_admin_mail
def send_admin_mail
UserMailer.send_welcome_email(self).deliver_later
end
end
You have set your route resources wrong.
devise_scope :user do
scope module: :users do
resources :registrations do
member do
delete :delete_image_attachment
end
end
end
end
You can read more about it here: https://rubyinrails.com/2019/04/16/rails-routes-difference-between-resource-and-resources/
When I try to access app/views/companies/courses/show.html.erb(which is redirected after app/views/companies/courses/new.html.erb), rails server says that it cannot find a course without an ID.
Also, when I run Course.all on rails console, the courses have the correct id, the correct description and the correct company id but no name attribute.
App/controllers/companies/courses_controller:
class Companies::CoursesController < ApplicationController
before_action :authenticate_company!
def new
#course = Course.new
end
def create
#course = current_company.courses.create(course_params)
if #course.save
redirect_to companycourse_path(:course => #course.id)
else
render 'new'
end
end
def show
#course = current_company.courses.find(params[:id])
end
def index
#courses = current_company.courses.all
end
private
def course_params
params.require(:course).permit(:title, :description)
end
end
App/models/course.rb:
class Course < ApplicationRecord
belongs_to :company
end
App/models/company.rb:
class Company < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :courses
end
Config/routes.rb:
Rails.application.routes.draw do
devise_for :companies
devise_for :users
root 'static_pages#home'
get 'users/:id' => 'users#show'
resources :users, only: [:show]
get 'companies/:id' => 'companies#show'
resources :companies, only: [:show] do
resources :courses, only: [:show,:new,:create,:index]
end
devise_scope :user do
get 'signup', to: 'users/registrations#new'
get 'login', to: 'users/sessions#new'
end
devise_scope :company do
get 'companysignup', to: 'companies/registrations#new'
get 'companylogin', to: 'companies/sessions#new'
get 'newcourse', to:'companies/courses#new'
post 'newcourse', to:'companies/courses#create'
get 'companycourse', to:'companies/courses#show'
get 'companycoursesindex', to:'companies/courses#index'
end
end
I had a similar problem building my app not long ago and my problem was coming from controllers.
In your routes.rb I would add resources :companies, :has_many => :courses.I also would add a validation to your course model in models/course.rb to make sure that when you save it to the database your object has a title: class Course < ApplicationRecord
belongs_to :company validates :title, presence: :true
end
Also try using this or something along lines in your courses_controller.rb instead of your current code:
def create
#company = find_company
#course = Course.new(course_params)
#course.company_id = current_company.id
if #course.save
your conditions here
else
your conditiona here
end
end
private
def find_company
params.each do |name, value|
if name == 'company_id'
return #company = Company.find(value.to_i)
end
end
nil
end
I hope it helps.
Hey there,
I am fairly new to Rails and I've managed to create a Favorite controller for my Items(Tools) and Users, which works totally fine.Now I am trying to do the same just in that user module. So users are able to favorite other users. I played around, and came up with this:
I am getting this error in the browser when accessing /users/index view:
NoMethodError in Users#index
undefined method `favorite_user_path' for #<#<Class:0x8ca77b8>:0x8ca50b8>
Here is my code:
app/models/favorite_user.rb
class FavoriteUser < ActiveRecord::Base
belongs_to :c_user_id
belongs_to :user_id
end
app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :tools
# Favorite tools of user
has_many :favorite_tools # just the 'relationships'
has_many :favorites, through: :favorite_tools, source: :tool # the actual tools the user favorites
# Favorite users of user
has_many :favorite_users # just the 'relationships'
has_many :userfavorites, through: :favorite_users, source: :user # the actual users the user favorites
has_many :userfavorited_by, through: :favourite_users, source: :user # the actual users favoriting a user
mount_uploader :avatar_filename, AvatarUploader
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :find_user, only: [:show, :favorite]
# Add and remove favorite recipes
# for current_user
def userfavorite
type = params[:type]
if type == "favorite"
current_user.userfavorites << #user
elsif type == "unfavorite"
current_user.userfavorites.delete(#user)
else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end
def index
#users = User.all
end
def show
#tools = Tool.where(user_id: #user).order("created_at DESC")
#tool = Tool.find(1)
end
private
def find_user
#user = User.find(params[:id])
end
end
app/views/users/index.html.haml
- #users.each do |user|
= image_tag gravatar_for user if user.use_gravatar == true
= image_tag user.avatar_filename.url if user.use_gravatar == false
%h2= link_to user.username, user
%p= link_to "Favorite", favorite_user_path(user, type: "favorite"), method: :get
%p= link_to "Unfavorite", favorite_user_path(user, type: "unfavorite"), method: :get
app/config/routes.rb
resources :users, only: [:index, :show, :userfavorite] do
get :userfavorite, on: :member
end
I hope the provided data is enough, if not please tell me. I'm grateful for all Your replies.
You haven't declared any such path in the routes file. As per your routes file you can use named path like
userfavorite_user_path(user_id)
I am getting an error "undefined method " when I try to build a nested resource on action 'new' in rails 4.2
Here's my routes:
devise_for :medics
resources :patients, shallow: true do
resources :consultations do
resources :prescriptions
end
end
I have Devise for system logon, and rather than use "User" to the model name, I use "Medic" in order to use the registry to devise to create a type of medical profile with a new fields like name, phone, etc. (I don't know if here's the problem)...
Patients controller:
class PatientsController < ApplicationController
before_action :set_medic
def new
#patient = #medic.patients.new
end
def create
#patient = #medic.patients.new(patient_params)
end
def set_medic
#medic = Medic.find_by_id(params[:medic_id])
end
Model:
class Medic < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :patients, :dependent => :destroy
end
class Patient < ActiveRecord::Base
belongs_to :medic, :foreign_key => :medic_id, :dependent => :destroy
has_many :consultations
accepts_nested_attributes_for :consultations
end
View:
<%= link_to 'New Patient', new_patient_path(#medic) %>
rake routes:
new_patient GET /patients/new(.:format) patients#new
Error:
undefined method `patients' for nil:NilClass
in this line: #patient = #medic.patients.new
Any idea? thaks in advance
The problem is very simple.
You're calling the following on each request:
def set_medic
#medic = Medic.find_by_id(params[:medic_id])
end
The problem is that you're not passing medic_id through your routes:
devise_for :medics
resources :patients, shallow: true do #-> no medic_id here
resources :consultations do #-> or here
resources :prescriptions #-> or here
end
end
Therefore, what happens is that you're trying to find a Medic without any id, hence the NilClass error.
You're getting confused with the nested resources directive in Rails routes:
#DON'T use this - it's just an example
#config/routes.rb
resources :medics do
resources :patients #-> url.com/medics/:medic_id/patients/:id
end
As you're using Devise, I think you'd be able to get away with scoping your calls around the current_medic helper (which is what I presume you're doing)...
-
Fix
#app/controllers/patients_controller.rb
class PatientsController < ApplicationController
def new
#patient = current_medic.patients.new
end
def create
#patient = current_medic.patients.new(patient_params)
end
end
This way, you'll be able to use (as you're using current_medic):
<%= link_to "New", new_patient_path %>
Since you didn't put the medic_id in your route, you probably have to clarify the parameter in your view like this:
<%= link_to 'New Patient', new_patient_path(:medic_id => #medic.id) %>
I start to use Socialization gem.
So, created User model with devise:
class User < ActiveRecord::Base
has_many :posts
devise :database_authenticatable,
:registerable,
:recoverable,
:rememberable,
:trackable,
:validatable
acts_as_follower
acts_as_followable
acts_as_liker
end
Then I created Post with scaffold:
class Post < ActiveRecord::Base
belongs_to :user
acts_as_likeable
end
And I want to allow user like posts. But I don't know how to create view with like button, also I dont know how to write methods for likes. Please give me little example. I'm new in rails
I create link in veiw/posts/show.html.erb.
<%= link_to "Like", like_post_path(#post),
:method => :post, :class => 'btn btn-primary btn-xs' %>
And method in app_contoller:
def like
#post = Post.find(params[:id])
current_user.like!(#post)
end
How to write route for this?
You can already test in your console to see how it works first: rails c
user = User.first
post = Post.first
user.like!(post)
user.likes?(post)
So you can create an action: likes in your Posts controller.
def likes
#user = current_user # before_action :authenticate_user, only: [:likes]
#post = Post.find(params[:id])
#user.like!(#post)
redirect_to :back, notice: "Liked this post successfully!"
end
And create a route for that action:
get 'post/:id/likes', to: 'posts#likes', as: :likes
And in your views:
<%= link_to 'like', likes_path(#post) %>