Make the Edit path the same as the show page in Devise - ruby-on-rails

In the profile page in my views I created an edit profile tab so the User can edit the profile in the show page. I am using a custom Devise controller but I am not sure how to tackle having the route for edit as the same as the show page.
This is my controller
class Teachers::RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create],
# before_action :configure_account_update_params, only: [:update]
#GET /resource/sign_up
def new
super
end
def sign_up_params
params.require(:teacher).permit(:name, :avatar, :email, :password)
end
#POST /resource/
def create
super
end
# GET /resource/edit
def edit
super
end
and this is my routes
Rails.application.routes.draw do
devise_for :teachers, controllers: { registrations: 'teachers/registrations' }
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: "teachers#index"
resources :teachers
resources :students
resources :courses
resources :behavior_reports
resources :participation_reports
resources :grades
resources :parents
resources :attendances
end

Related

No route matches [GET] "/admin/products" although there is one in rake routes

can I get your help on the error? I keep getting this oneπŸ‘‰
enter image description here
My routes πŸ‘‰
enter image description here
Rails.application.routes.draw do
root 'static_pages#home'
resources :products, only: :show
devise_for :users
devise_scope :user do
authenticate :user, ->(u) { u.admin? } do
namespace :admin do
resources :products
end
end
end
end
And Controller πŸ‘‰
enter image description here
class Admin::ProductsController < ApplicationController
before_action :authenticate_user!
def index; end
end

Adding a concern to the controller causes AbstractController::ActionNotFound

I use the same set_modpack method in several controllers, and I decided to make a concern for it. But when I add the concern to the controller, all routes give me AbstractController::ActionNotFound error.
My routes:
concern :commentable do
resources :comments, shallow: true
end
resources :modpacks, concerns: :commentable do
resources :releases, controller: 'modpack_releases'
end
My concern:
# app/controllers/concerns/modpack_derivative.rb
module ModpackDerivative
extend ActiveSupport::Concern
protected
def set_modpack
#modpack = Modpack.find(params[:id])
if #modpack.nil?
#modpack = Modpack.find_by!(slug: params[:id])
end
end
end
My controller:
# app/controllers/modpacks_controllers.rb
class ModpacksController < ApplicationController
include ModpackDerivative
before_action :set_modpack, only: [:show, :update, :destroy]
# 100% standard index, create, show,
# update and destroy actions (API)
private
def modpack_params
params.require(:modpack).permit(:logo, :name, :slug, :summary, :tags, :description)
end
end
It works fine if I delete the concern and paste the set_modpack methods inside the controllers.

Rails 5 routing resources using custom actions

About routing, If I do something like this:
resources :students
resources :teachers
I will get something like:
students GET /students(.:format) students#index
...
teachers GET /teachers(.:format) teachers#index
...
Changing to:
resources :students, controller: :users
resources :teachers, controller: :users
will give me:
students GET /students(.:format) users#index
teachers GET /teachers(.:format) users#index
Note that now, both resources are using the same controller Users and the same action index. But what I need, instead of using the same index action, is the students resource to use actions prefixed by students like students_index and teachers resources prefixed by teachers like teacher_index.
In other words, I want bin/rails routes to give me the following output:
students GET /students(.:format) users#students_index
teachers GET /teachers(.:format) users#teachers_index
I know that I can do the same with:
get 'students', to: 'users#students_index'
But there is a way to do the same with resources?
I don't think there's a way to do that with resources helper. What you could do (if it's only the index action you wanna override) is add an except, like this:
resources :students, controller: :users, except: [:index]
resources :teachers, controller: :users, except: [:index]
then, as you already suggested, do the individuals index actions like that:
get 'students', to: 'users#students_index', as: :student
get 'teachers', to: 'users#teachers_index', as: :teacher
Or you could reconsider the structure of your controllers... Good luck!
There is a far better way to do this as you might have surmised - inheritance.
# app/controllers/users_controller.rb
class UsersController < ApplicationController
delegate :singular, :plural, :param_key, to: :model_name
before_action :set_resource, only: [:show, :edit, :update, :destroy]
before_action :set_resources, only: [:index]
def initialize
#model_name = resource_class.model_name
super
end
def show
end
def index
end
def new
#resource = resource_class.new
set_resource
end
def create
#resource = resource_class.new(permitted_attributes)
if #resource.save
redirect_to #resource
else
set_resource
render :new
end
end
def edit
end
def update
if #resource.update(permitted_attributes)
redirect_to #resource
else
set_resource
render :edit
end
end
def destroy
#resource.destroy
redirect_to action: "index"
end
# ...
private
# Deduces the class of the model based on the controller name
# TeachersController would try to resolve Teacher for example.
def resource_class
#resource_class ||= controller_name.classify.constantize
end
# will set #resource as well as #teacher or #student
def set_resource
#resource ||= resource_class.find(params[:id])
instance_variable_set("##{singular}", #resource)
end
# will set #resources as well as #teachers or #students
def set_resources
#resources ||= resource_class.all
instance_variable_set("##{plural}", #resources)
end
def permitted_attributes
params.require(param_key).permit(:a, :b, :c)
end
end
# app/controllers/teachers_controller.rb
class TeachersController < UsersController
end
# app/controllers/students_controller.rb
class StudentsController < UsersController
end
# routes.rb
resources :students
resources :teachers
This lets you follow the regular Rails convention over configuration approach when it comes to naming actions and views.
The UsersController base class uses quite a bit of magic through ActiveModel::Naming both to figure out the model class and stuff like what to name the instance variables and the params keys.

Routing for sub ressources in rails

So this is in routes file :
resources :users do
resources :lamps
end
I want to be able to display a user's "lamps" with something like :
http://localhost:3000/users/2/lamps
and show all the existing lamps whichever user owns it using :
http://localhost:3000/lamps
both are very different as the first one is more of a management view and the later is more what a user browsing would see.
The thing is they both go to the index action of the lamp_controller
How can I manage this in a clean way without having to use if statements in my action/view?
You can use the module option to route the nested routes to a namespaced controller:
Rails.application.routes.draw do
resources :users do
resources :lamps, only: [:index], module: 'users'
end
resources :lamps, only: [:index]
end
Another way to do this for a group of resources is:
Rails.application.routes.draw do
resources :users do
scope module: 'users' do
resources :lamps, only: [:index]
resources :chairs
resources :rugs
end
end
resources :lamps, only: [:index]
end
This would let you handle the different contexts in separate controllers:
# app/controllers/lamps_controller.rb
class LampsController < ApplicationController
# GET /lamps
def index
#lamps = Lamp.all
end
end
# app/controllers/users/lamps_controller.rb
class Users::LampsController < ApplicationController
before_action :set_user
# GET /users/:user_id/lamps
def index
#lamps = #user.lamps
# renders /views/users/lamps/index.html.erb
end
private
def set_user
#user = User.find(params[:user_id])
end
end

What is the RESTful and Rails way to add these actions to my controller

I am adding tagging functionality to my app, via acts_as_taggable_on.
That gem doesn't add controllers, but I would like to. I am adding the tagging functionality to my Node model.
On my NodeController, I know I could simply add the explicit actions like this:
def add_tagged_user
end
def remove_tagged_user
end
def tagged_users
end
But that doesn't feel very restful or Railsy.
The corresponding route would look like this:
resources :nodes do
match :add_tagged_user, via: [:post], on: :member
match :remove_tagged_user, via: [:delete], on: :member
match :tagged_users, via: [:get], on: :member
end
Is there a RESTful or a more Railsy way to do this?
You could go with a single TagsController, with routes that match the RESTful resource(s).
Something like
Routes
# routes.rb
resources :nodes do
resources :tags, only: [:show, :create, :update]
end
resources :other_resources do
resources :tags, only: [:show, :create, :update]
end
Controller
class TagsController < ApplicationController
before_action :load_taggable
def create
#taggable.tags.create(tag_params)
end
private
def load_taggable
# switches on params
#taggable = if params[:node_id]
Node.find(params[:node_id]
elsif # other things that are taggable
# OtherThing.find(...)
end
end
end

Resources