No route matches ... missing required keys - ruby-on-rails

I have two controllers and models Projects and Schemas. Schemas belongs_to projects. Projects has_many schemas. I am looking for http://localhost:3000/projects/SLUG-PROJECT/schemas/SLUG-SCHEMA.
Following is my SchemaController code:
class Projects::SchemasController < ApplicationController
before_action :set_schema, only: [:show, :edit, :update, :destroy]
before_action :set_project, only: [:index, :show, :new, :edit, :update, :destroy]
def index
#schemas = Schema.all
end
def show
end
def new
#schema = Schema.new
end
def edit
end
def create
#schema = Schema.new(schema_params)
respond_to do |format|
if #schema.save
format.html { redirect_to project_url(#schema.project_id), notice: 'Schema was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #schema.update(schema_params)
format.html { redirect_to project_url(#schema.project_id), notice: 'Schema was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
#schema.destroy
respond_to do |format|
format.html { redirect_to project_url(#schema.project_id), notice: 'Schema was successfully destroyed.' }
end
end
private
def set_schema
#schema = Schema.find(params[:id])
end
def set_project
#project = Project.friendly.find(params[:project_id])
end
def schema_params
params.require(:schema).permit(:number, :identification, :reference, :name, :description, :author, :controller, :priority, :notes, :status, :cycle, :slug, :project_id)
end
end
This is my code:
respond_to do |format|
if #schema.update(schema_params)
format.html { redirect_to project_url(#schema.project_id), notice: 'Schema was successfully updated.' }
else
format.html { render :edit }
end
It works for index and show pages, but I get the following error for update, edit, and destroy:
ActionController::UrlGenerationError in Projects::SchemasController#update
No route matches {:action=>"show", :controller=>"projects", :id=>nil} missing required keys: [:id]
Can anybody help me figure out what is going on?

What you’re looking for is nested routes. In this case you could include this route declaration:
resources :projects do
resources :schemas
end
In addition to the routes for projects, this declaration will also route schemas to an SchemasController. The schema URLs require a project:
/projects/:project_id/schemas/:id
This will also create routing helpers such as project_schemas_url and edit_project_schema_path. These helpers take an instance of Project as the first parameter: project_schemas_url(#project).
And remember to always instantiate schemas on an existing project, say:
#project.schemas.build

Related

Ruby-on-Rails NoMethodError in my controller undefined method `user_id' for nil:NilClass

My ruby application is throwing an error which has appeared all of a sudden. the error thrown is NoMethodError in JobsDevsController # listing=> undefined method `user_id' for nil:NilClass
The part of my code that throws this error in my controller is
def is_authorised
redirect_to root_path, alert: "You don't have permission..." unless current_user.id == #job.user_id
end
My Controller
class JobsDevsController < ApplicationController
before_action :set_jobs_dev , except: [:index, :new, :create, :show, :edit, :listing]
before_action :authenticate_user!, except: [:show, :listing]
before_action :is_authorised, only: [:listing, :budget, :description, :photo_upload, :location, :update, :show ]
# GET /jobs_devs
def index
#jobs_devs = JobsDev.all
end
# GET /jobs_devs/1
def show
end
# GET /jobs_devs/new
def new
#jobs_dev = current_user.jobs_devs.build
end
# def listing
# #jobs_dev = current_user.jobs_dev
# end
# GET /jobs_devs/1/edit
def edit
end
def budget
end
# POST /jobs_devs
def create
#jobs_dev = current_user.jobs_devs.build(jobs_dev_params)
if #jobs_dev.save!
redirect_to listing_jobs_dev_path(#jobs_dev), notice: 'Jobs dev was successfully created.'
else
render :new
end
end
# PATCH/PUT /jobs_devs/1
# def update
# if #jobs_dev.update(jobs_dev_params)
# redirect_to #jobs_dev, notice: 'Jobs dev was successfully updated.'
# else
# render :edit
# end
# end
def update
respond_to do |format|
if #jobs_dev.update(jobs_dev_params)
format.html { redirect_to #jobs_dev, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #jobs_dev }
else
format.html { render :edit }
format.json { render json: #jobs_dev.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs_devs/1
def destroy
#jobs_dev.destroy
redirect_to jobs_devs_url, notice: 'Jobs dev was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_jobs_dev
#jobs_dev = JobsDev.find(params[:id])
end
def is_authorised
redirect_to root_path, alert: "You don't have permission..." unless current_user.id == #jobs_dev.user_id
end
# Only allow a trusted parameter "white list" through.
def jobs_dev_params
params.require(:jobs_dev).permit(:job_category, :job_type, :job_title, :job_description, :recurrence,
:budget, images: []
)
end
end
Please can you help with this senario
Make sure you set_job for listing actiton
You may need to add to the listing action directly
#job = current_user.job
or the better way to add it to before action of listing action and take order into consideration
Looks like your is_authorised method is looking for #job, which isn't set in your controller; rather, you assign #jobs_dev.
Update the method to the following:
def is_authorised
redirect_to root_path, alert: "You don't have permission..." unless current_user.id == #jobs_dev.user_id
end
I'm not sure that's sufficient, as you're skipping setting this in your before_action:
before_action :set_jobs_dev , except: [:index, :new, :create, :show, :edit, :listing]
It looks as if you'll need to remove :listing from the except clause there.
Try both of these things and it should work again. Let me know if you've any questions or have any issues with this :)

Rails redirect after destroy action

I have a model named Group which has_many Posts and each Post has_many Comments. I can navigate to a group, create a post and then create a comment under that post. My issue is when I try and delete a comment I receive the below error about the redirect (the comment is deleted the redirect just doesn't happen).
undefined method `id' for nil:NilClass
this is the line in my destry action it does not like, which is weird because my update action has the same redirect and that works fine.
format.html { redirect_to group_post_url(group_id: #group.id, id: #post), notice: 'Comment was successfully destroyed.' }
I tried adding [:destroy] onto the set_post before_action thinking that it might need that but no luck.
here's some of my routes
group_posts GET /groups/:group_id/posts(.:format) posts#index
POST /groups/:group_id/posts(.:format) posts#create
new_group_post GET /groups/:group_id/posts/new(.:format) posts#new
edit_group_post GET /groups/:group_id/posts/:id/edit(.:format) posts#edit
group_post GET /groups/:group_id/posts/:id(.:format) posts#show
PATCH /groups/:group_id/posts/:id(.:format) posts#update
PUT /groups/:group_id/posts/:id(.:format) posts#update
DELETE /groups/:group_id/posts/:id(.:format) posts#destroy
groups GET /groups(.:format) groups#index
POST /groups(.:format) groups#create
here's my comments_controller.rb
class CommentsController < ApplicationController
before_action :set_group, only: [:index, :show, :new, :edit, :create, :update]
before_action :set_post, only: [:index, :show, :new, :edit, :create, :update]
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /posts/:post_id/comments
def index
#comments = #post.comments.order(created_at: :desc)
end
def show
end
# GET /posts/:post_id/comments/new
def new
#comment = #post.comments.new
end
# # GET /posts/:post_id/comments/edit
# def edit
# end
# POST /posts/:post_id/comments
def create
# inserts current_user into the comments foriegn key for user_id.
#comment = #post.comments.new(comment_params.merge(user_id: current_user.id))
respond_to do |format|
if #comment.save
format.html { redirect_to group_post_url(group_id: #group.id, id: #post), notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/:post_id/comments/:id
def update
respond_to do |format|
if #post.comments.update(comment_params)
format.html { redirect_to group_post_url(group_id: #group.id, id: #post), notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/:post_id/comments/:id
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to group_post_url(group_id: #group.id, id: #post), notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
###################
# private methods
###################
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
def set_post
#post = Post.find(params[:post_id])
end
def set_group
#group = Group.find(params[:group_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:content, :post_id, :user_id)
end
end
If you'd like to reference the #group instance variable, you should add :destroy to the before_action set_group callback:
before_action :set_group, only: [:index, :show, :new, :edit, :create, :update, :destroy]
You should also add :destroy to the before_action set_post callback as well

Can't redirect Devise sign page to show profile

I'm hoping someone can help. I am using the Devise gem for registering and signing in users. I have a Profile controller. When an existing user logs in, I want them to be diverted to the Profile's show.html.erb page in order to view their profile. I would expect this would be done under the Sessions controller but it doesn't seem to do anything
The Sessions controller code is:
class Registrations::SessionsController < Devise::SessionsController
# before_action :configure_sign_in_params, only: [:create]
protected
def after_sign_in_path_for(resource)
profile_path(resource)
end
However, when a user registers, the redirect works successfully under the Registrations controller below:
class RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
protected
def after_sign_up_path_for(resource)
new_profile_path(resource)
end.
I also want to have a link to the users Profile page when they are logged in but when I do it throws up the following error
application.html.erb code for the link is below (I have tried a number of different variables in place of the '#profile' but with no success)
<li><%= link_to 'Show Profile', profile_path(#profile), :class => 'navbar-link' %></li>
The error I receive is:
ActionController::UrlGenerationError in Profiles#index
No route matches {:action=>"show", :controller=>"profiles", :id=>nil} missing required keys: [:id]
My routes (which I'm not sure are setup correctly:
Rails.application.routes.draw do
resources :profiles
get 'profiles/:id', to: 'profiles#show'
get '/profiles/new' => 'profiles#new'
get '/profiles/edit' => 'profiles#edit'
get '/profiles/index' => 'profiles#index'
root to: 'pages#index'
devise_for :users, :controllers => { :registrations => "registrations" }
Lastly, my Profile controller:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
def index
#search = Profile.search(params[:q])
#profiles = #search.result(distinct: true)
end
def show
#profile = Profile.find(params[:id])
end
def new
#profile = Profile.new
end
def create
#profile = Profile.new(profile_params)
respond_to do |format|
if #profile.save
format.html { redirect_to #profile, notice: 'Your Profile was successfully created' }
format.json { render :show, status: :created, location: #profile }
else
format.html { render :new }
format.json { render json: #profile.errors, status: :unprocessable_entry }
end
end
end
def edit
#profile = Profile.find(params[:id])
end
def update
respond_to do |format|
if #profile.update(profile_params)
format.html { redirect_to #profile, notice: 'Profile was successfully updated.' }
format.json { render :show, status: :ok, location: #profile }
else
format.html { render :edit }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
def destroy
#profile.destroy
respond_to do |format|
format.html { redirect_to profile_url, notice: 'Profile was successfully destroyed.' }
format.json { head :no_content }
end
end
def set_profile
#profile = Profile.find(params[:id])
end
private
def profile_params
params[:profile][:user_id] = current_user.id
params.require(:profile).permit(:full_name, :contact_number, :location, :makeup_type, :bio, :user_id, :image)
end
end
Any help is most appreciated.
Ok so there are two problems:
Redirecting after sign in
Url generation error in the application layout
Redirecting after sign in
You need to add the controller to your routes definition (like you have registrations.
devise_for :users, controllers: { registrations: "registrations", sessions: 'registrations/sessions' }
Url generation error in the application layout
I assume that the profile model is associated with the user (e.g. profile belongs_to user, or maybe user has_one profile). I also assume that you want to have a link for the current user's profile.
If that is the case then you could most likely do something like this:
<%= if current_user %>
<li>
<%= link_to 'Show Profile', profile_path(current_user.profile), :class => 'navbar-link' %>
</li>
<% end %>
Otherwise, you should set #profile in some before_action in the application controller or in any controller that uses the application layout.
In your application controller you want something like this
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(user)
profile_path(current_user)
end
#user is the model name for example that you created with devise
end

Rails association new_path error

I have two models post and topic in my rails app
class Post < ActiveRecord::Base
#relation between topics and post
belongs_to :topic
#post is valid only if it's associated with a topic:
validates :topic_id, :presence => true
#can also require that the referenced topic itself be valid
#in order for the post to be valid:
validates_associated :topic
end
And
class Topic < ActiveRecord::Base
#relation between topics and post
has_many :posts
end
I am trying to create association between both of them.
I want multiple post corresponding to each topic
I have used nested routes
Rails.application.routes.draw do
# nested routes
resources :topics do
resources :posts
end
resources :userdetails
devise_for :users, :controllers => { :registrations => "registrations" }
My Post controller looks like
class PostsController < ApplicationController
# before_action :set_post, only: [:show, :edit, :update, :destroy]
before_filter :has_userdetail_and_topic, :only =>[:new, :create]
# GET /posts
# GET /posts.json
#for new association SAAS book
protected
def has_userdetail_and_topic
unless(#topic =Topic.find_by_id(params[:topic_id]))
flash[:warning] = 'post must be for an existing topic'
end
end
public
def new
#post = #topic.posts.build
###topic = Topic.find(params[:topic_id1])
end
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
##topic.posts << #post
##current_user = current_user.id
#current_user.posts << #topic.posts.build(params[:post])
##post = Post.new(post_params )
##post.userdetail_id = current_user.id
#Association functional between topic and post
#Class variable used
###topic.posts << #post
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:topic_id,:issue, :description, :rating, :userdetail_id)
end
end
I am trying to navigate from topics/index via code <td><%= link_to 'Write', new_topic_post_path(#topic) %> </td>
but when i try to go at localhost:3000/topics]
I am getting error
No route matches {:action=>"new", :controller=>"posts", :topic_id=>nil} missing required keys: [:topic_id]
Can any body tell me about this error, as i am new to rails please clearly specify answer.
And I have one more doubt, please tell me if i am doing association between topic and post incorrectly.I have confusion about this line of code -
#topic.posts << #post
What the error missing required keys: [:topic_id] is telling you is that you need to provide a hash with the key topic_id:
<%= link_to 'Write', new_topic_post_path(topic_id: #topic) %>
Passing a resource as to a route helper only works for the id param:
<%= link_to #topic, topic_path(#topic) %>
Is a kind of shorthand for:
<%= link_to #topic, topic_path(id: #topic.to_param) %>
Addition:
#prcu is also correct. The #topic record needs to be saved to the database. Records which are not saved do not have an id since the database assigns the id column when the record is inserted.
You also need to set the #topic instance variable in PostsController:
#topic = Topic.find(params[:id])
This is commonly done with a before filter:
before_filter :set_topic, only: [:new]
def set_topic
#topic = Topic.find(params[:id])
end
The same also need to be done in TopicsController#index.
#topic is not set or it's not persisted. You can not use topic not saved to db in this helper.

Active Model Forbidden attributes error

would someone be able to help me understand this error. I am trying to create a contact form in rails following the building web apps tutorial. I followed the steps to generate a message scaffold. I then amended my routes. Next it said to put this into the messages controller show action.
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
I have done this and i am getting the following error
ActiveModel::ForbiddenAttributesError in MessagesController#create
ActiveModel::ForbiddenAttributesError
This is my message controller file
class MessagesController < InheritedResources::Base
def show
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
end
end
end
My routes file is as follows
# devise_for :users
resources :products do
resources :orders, only: [:new, :create]
#tells rails needs product id number
end
# get 'pages/payment'
get 'home/about'
get 'messages/new'
get 'seller' => "products#seller"
get 'sales' => "orders#sales"
get 'static_pages/productlanding'
get "content/veg"
get "content/fruit"
get "content/mix"
get 'subscriptions/new'
root 'static_pages#home'
Why are you saving in the show action?
--
Params
The ForbiddenAttributes error stems from the strong_params functionality of Rails.
When saving data, you're meant to pass the params through to your model through a strong_params method. This is typically achieved with the following setup:
#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def show
#message = Message.find(params[:id])
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
#message.save
end
private
def message_params
params.require(:message).permit(:your, :message, :params)
end
end
This is how your controller should really be constructed. Your error, I believe, is caused by your lack of params to pass through to the attributes in your model (hence your call to #save resulting in trying to populate your model with non-data).
Strange. You execute saving method in "show" method of controller which responsible for showing up the content on the separate page.
You should replace as following:
def create
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
end
end
i have managed to sort this with the following! Thanks for all the help
class MessagesController < ApplicationController
before_action :set_message, only: [:show, :edit, :update, :destroy]
# GET /messages
# GET /messages.json
def index
#messages = Message.all
end
# GET /messages/1
# GET /messages/1.json
def show
end
# GET /messages/new
def new
#message = Message.new
end
# GET /messages/1/edit
def edit
end
# POST /messages
# POST /messages.json
def create
#message = Message.new(message_params)
respond_to do |format|
if #message.save
flash.now[:notice] = 'Thank you for your message!'
format.html { redirect_to root_path }
format.json { render :show, status: :created, location: #message }
else
format.html { render :new }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /messages/1
# PATCH/PUT /messages/1.json
def update
respond_to do |format|
if #message.update(message_params)
format.html { redirect_to #message, notice: 'Message was successfully updated.' }
format.json { render :show, status: :ok, location: #message }
else
format.html { render :edit }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
# DELETE /messages/1
# DELETE /messages/1.json
def destroy
#message.destroy
respond_to do |format|
format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_message
#message = Message.find(params[:id])
end
.
def message_params
params.require(:message).permit(:name, :email, :company, :phone, :subject, :body)
end
end
I was facing this same error. The fix was to make the params function name same as the root tag of the post json like below
Post json
{"jobseeker_certificate":{"id":-1,"name":"First Class Medical Certificate","institute":"GACA","attachment":null}}
In Controller i changed jobseeker_aircraft_type_ratings_params to jobseeker_certificate_params
def jobseeker_certificate_params
params.require(:jobseeker_certificate).permit(:aircraft, :total_time, :pilot_in_command,
:co_pilot, :rating_expiry_date, :from, :to, :jobseeker_id, :grade, :institute, :attachment, :name,
:from, :to, :jobseeker_id, :grade, :institute, :attachment, :name, :sector_id, :certificate_type,
:details, :certificate_type, :details)
end

Resources