Rails 4 routing error when scaffolding - ruby-on-rails

After performing a rails g scaffold Project name:string, I get a routing error when I create a new project.
My steps:
1) on /projects, I click 'New Project'.
2) I fill the project details and click 'Create Project'.
In this step the form seems to be correct:
form accept-charset="UTF-8" action="/projects" class="new_project" id="new_project" method="post"
3) I get the following error (routing error): No route matches [POST] "/projects/new"
Whereas:
when I reload the /projects/new page, the creation of the project works fine
Any reason for this?

Below are the files I have (I created most of them with the scaffolding)
app/models/project.rb:
class Project < ActiveRecord::Base
end
app/controllers/projects_controller.rb: (I only show here the methods that we re interested in)
class ProjectsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
before_action :set_project, only: [:show, :edit, :update, :destroy]
# GET /projects/new
def new
#project = Project.new
end
# GET /projects/1/edit
def edit
end
# POST /projects
# POST /projects.json
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render action: 'show', status: :created, location: #project }
else
format.html { render action: 'new' }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /projects/1
# PATCH/PUT /projects/1.json
def update
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_project
#project = Project.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:name)
end
end
and config/routes.rb:
Testproject::Application.routes.draw do
devise_for :users
resources :projects
root 'projects#index'
end
Thanks for your help

Related

Cannot delete records in Rails

I have three models: Project, team and users.
Team has many projects associated.
In my projects def I want to delete teams associated to projects but nothing happens when I click delete.
My destroy def is as follows:
def destroy
#project = Project.find(params[:id])
#team = project.team
#project.destroy
# edit #1 shown below:
respond_to do |format|
format.html { redirect_to #team, notice: 'Project was successfully destroyed.' }
end
end
And making the button inside show.erb.html to delete project and link back to project path
<%= link_to 'Delete Project', project_path(#project), data: { confirm: 'Are you sure'}, method: :destroy, class:'button is-danger is-outlined' %>
</div>
Routes:
Rails.application.routes.draw do
resources :projects
resources :teams
as :user do
put '/user/confirmation' => 'confirmations#update', :via => :patch, :as => :update_user_confirmation
end
devise_for :users, controllers: {
registrations: 'registrations',
confirmations: 'confirmations'
}
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end
root 'home#index'
end
I'm still very new to rails and cannot find a reason for why this may be occuring.
Edit 2 - More details
Projects Controller is as follows:
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:edit, :update, :destroy]
# GET /projects
# GET /projects.json
def index
#projects = Project.all.order('created_at DESC')
end
# GET /projects/1
# GET /projects/1.json
def show
end
# GET /projects/new
def new
#project = current_user.projects.build
#teams = Team.where('id = ?', current_user.team_id)
end
# GET /projects/1/edit
def edit
#teams = current_user.teams
end
# POST /projects
# POST /projects.json
def create
#project = current_user.projects.build(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /projects/1
# PATCH/PUT /projects/1.json
def update
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { render :show, status: :ok, location: #project }
else
format.html { render :edit }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
# DELETE /projects/1
# DELETE /projects/1.json
def destroy
#project = Project.find(params[:id])
#team = project.team
#project.destroy
# edit #1 shown below:
respond_to do |format|
format.html { redirect_to #team, notice: 'Project was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_project
#project = Project.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:name, :description, :team_id)
end
end
Redirecting to a resource after you delete it doesn't work, because that resource no longer exists. So the controller action should probably redirect to the deleted projects team:
def destroy
#project = Project.find(params[:id])
#team = project.team
#project.destroy
# edit #1 shown below:
respond_to do |format|
format.html { redirect_to #team, notice: 'Project was successfully destroyed.' }
end
end
Then your link_to should use method: :delete, NOT method: :destroy:
<%= link_to 'Delete Project', project_path(#project), data: { confirm: 'Are you sure'}, method: :delete, class:'button is-danger is-outlined' %>
Ref: https://api.rubyonrails.org/v5.2.3/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to-label-Options
See if that gets you going, and if not please share some debugging information.
Edit #1:
In your controllers destroy action, you need to do a little more work to handle how rails responds to requests. I didn't notice it missing before but the action should have a respond_to block where you can choose to respond different ways basically. I modified the above controller action code to give you an example.

Rails error: Couldn't find Node with 'id'=index?

I generate a node to show node name, but error . Here is the codo.
controllers/nodes_controller.rb (default)
class NodesController < ApplicationController
before_action :set_node, only: [:show, :edit, :update, :destroy]
def index
#nodes = Node.all
end
def show
#node = Node.find(params[:id])
end
def new
#node = Node.new
end
def edit
end
def create
#list = Node.new(node_params)
respond_to do |format|
if #node.save
format.html { redirect_to #node, notice: 'Node was successfully created.' }
format.json { render :show, status: :created, location: #node }
else
format.html { render :new }
format.json { render json: #list.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /lists/1
# PATCH/PUT /lists/1.json
def update
respond_to do |format|
if #node.update(node_params)
format.html { redirect_to #node, notice: 'Node was successfully updated.' }
format.json { render :show, status: :ok, location: #node }
else
format.html { render :edit }
format.json { render json: #node.errors, status: :unprocessable_entity }
end
end
end
# DELETE /lists/1
# DELETE /lists/1.json
def destroy
#node.destroy
respond_to do |format|
format.html { redirect_to nodes_url, notice: 'Node was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_node
#node = Node.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def node_params
params.require(:node).permit(:name, :summary)
end
end
models/node.rb
class Node < ActiveRecord::Base
has_many :lists
end
views/nodes/index.html.erb
<div class="nodes_list">
nodes: <br> <br>
<% nodes.each do |node| %>
<button class="secondary hollow button tiny">
<% if list.node %>
<%= link_to node.name, node %>
<% end %>
</button>
<% end %>
</div>
routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
resources :lists, only: [:index, :show, :new, :create]
resources :nodes, only: [:show, :index, :create, :new]
root 'lists#index'
end
rails s http://localhost:3000/nodes/index
ActiveRecord::RecordNotFound in NodesController#show
Couldn't find Node with 'id'=index
Extracted source (around line #61):
# Use callbacks to share common setup or constraints between actions.
60 def set_node
61 #node = Node.find(params[:id])
62 end
Request
Parameters:
{"id"=>"index"}
What should I do? How to debug? Thanks tell me.
You don't need to hit http://localhost:3000/nodes/index for the index action to be invoked in Rails controller. All you have to do is to go for http://localhost:3000/nodes, and it will hit the index action in your controller.
Anything like http://localhost:3000/nodes/something will take you to show action, and something will be taken as id to find a particular node. And since you are hitting: http://localhost:3000/nodes/index, so Rails is taking index as id to find a particular node.
Stick with the Rails convention, and REST principles, and let the magic of Rails take care of the things, and it sticks the following routes to particular actions:
GET: http://localhost:3000/nodes ----> Nodes#index
GET: http://localhost:3000/nodes/something ------> Nodes#show

Ruby on Rails API how to soft delete an user

I am able to soft delete an user from the main application.
Here are the details.
The user URL is:
http://0.0.0.0:3000/users/4c7fa12c-3d58-480b-a823-6c67d6e7f0fe.json
Which is presenting a JSON result like this:
{"id":"4c7fa12c-3d58-480b-a823-6c67d6e7f0fe","name":"John","status":"Active","created_at":"2015-11-10T18:31:27.000+00:00","updated_at":"2015-11-10T18:38:20.000+00:00"}
I can do a soft delete by using an inactivation this way:
http://0.0.0.0:3000/users/4c7fa12c-3d58-480b-a823-6c67d6e7f0fe/inactivate
Here is my inactivate method in the users controller:
def inactivate
#user.update status: 'Inactive'
redirect_to users_url
end
The result is shown when reload the user URL:
{"id":"4c7fa12c-3d58-480b-a823-6c67d6e7f0fe","name":"John","status":"Inactive","created_at":"2015-11-10T18:31:27.000+00:00","updated_at":"2015-11-10T19:29:58.000+00:00"}
Now my user is "Inactive".
Here is my routes file:
Rails.application.routes.draw do
resources :wit_dims
resources :wokas
resources :posts
resources :languages
resources :users
root :to => "home#index"
resources :users do
get 'inactivate', on: :member
end
match 'inactivate', to: 'users#inactivate', via: 'delete'
#api
namespace :api do
namespace :v1 do
resources :users, only: [:index, :create, :show, :update, :destroy]
resources :posts, only: [:index, :create, :show, :update, :destroy]
end
end
end
How I can change this routes file and the API users controller to make the same king of inactivation through the API? I want more than a trivial solution using a PUT to change status of the user from Active to Inactive.
Here is my main application users controller:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :inactivate]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully inactivated.' }
format.json { head :no_content }
end
end
def inactivate
#user.update status: 'Inactive'
redirect_to users_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params[:user]
end
end
Here is my API users controller:
class Api::V1::UsersController < Api::V1::BaseController
before_action :set_user, only: [:show, :update, :destroy]
def show
render(json: Api::V1::UserSerializer.new(#user).to_json)
end
def update
if #user.update_attributes(user_params)
render(
json: Api::V1::UserSerializer.new(#user).to_json,
status: 200,
location: api_v1_user_path(#user.id)
)
else
return api_error(status: 422, errors: #tbm.errors)
end
end
def index
users = User.all
render(
json: ActiveModel::ArraySerializer.new(
users,
each_serializer: Api::V1::UserSerializer,
root: 'users'
)
)
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :status).delete_if{ |k,v| v.nil? }
end
end
Basically I would like to be able to call an inactivate method through the API which is going to change the status from Active to Inactive, instead of physically deleting / destroying the user.
I used PUT and executed an updated on the status attribute to mark the user as Inactive.

Rails URL routing and grouping posts based on topic

I am new to rails I created post model and posts_controller which has Name:string, EMail:string, Message:text, topic_id:integer columns using scaffold.
I also created a topic model and topics_controller which has Topic_Name:string in it.
I provided the relationship among the models as follows:
class Topic < ActiveRecord::Base
has_many :posts, foreign_key: 'topic_id'
end
class Post < ActiveRecord::Base
belongs_to :topic
end
In routes.db I created the nested resources as:
resources :topics do
resources :posts
end
topics_controller.rb code:
class TopicsController < ApplicationController
before_action :set_topic, only: [:show, :edit, :update, :destroy]
# GET /topics
# GET /topics.json
def index
#topics = Topic.all
end
# GET /topics/1
# GET /topics/1.json
def show
end
# GET /topics/new
def new
#topic = Topic.new
end
# GET /topics/1/edit
def edit
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(topic_params)
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render :show, status: :created, location: #topic }
else
format.html { render :new }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /topics/1
# PATCH/PUT /topics/1.json
def update
respond_to do |format|
if #topic.update(topic_params)
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { render :show, status: :ok, location: #topic }
else
format.html { render :edit }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url, notice: 'Topic was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_topic
#topic = Topic.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def topic_params
params.require(:topic).permit(:Name)
end
end
posts_controller code:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
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(:Name, :Email, :Message, :topic_id)
end
end
I need to group posts using the topic. i.e., On clicking show on a particular topic it should go to the URL /topics/<topic_id>/posts where it should lists all posts related to that topic and I can create/delete posts belongs to that topic.
Can anyone help doing this..
Thank you..
Your question should be more direct, there's a lot of information that aren't related to the problem (the attributes names, for example), and your goal isn't clear enough.
It seems that you just want to setup the routes, right? You already have all posts related to that topic though the association: topic.posts. You just need to setup nested resource routes for posts:
resources :topics do
resources :posts
end
Also, you don't need the foreign_key option since you're using the naming conventions. It seems as well that you named some attributes in upper case, they should be name, email and message.
UPDATE:
In the index action, since you want posts belonging to one topic, you need to scope the #posts instance variable. Since you're using nested resources, you have the parameter params[:topic_id], so just fetch the topic with #topic = Topic.find(params[:topic_id]), then scope the association with #posts = #topic.posts. You'll need to do the same for every other action. I recommend that you read a little about associations in Rails, you'll probably need to use methods like #topic.posts.build and #topic.posts.find(params[:id]).
I found the solution for this problem in this link: Nested resources
Download the source code and find the solution...

Rails 4 : How to disable the Edit, Destroy etc,

Can I disable the "Edit" and "Destory" in the Rails ?for example, if I want to disable the "Edit" for everyone,what show I do in the test_controller.rb ? or anything else?
I am new to Rails, thanks in advance!
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update,:destroy ]
# GET /books
# GET /books.json
def index
#books = Book.all
end
# GET /books/1
# GET /books/1.json
def show
end
# GET /books/new
def new
#book = Book.new
end
# GET /books/1/edit
def edit
end
# POST /books
# POST /books.json
def create
#book = Book.new(book_params)
respond_to do |format|
if #book.save
format.html { redirect_to #book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: #book }
else
format.html { render :new }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /books/1
# PATCH/PUT /books/1.json
def update
respond_to do |format|
if #book.update(book_params)
format.html { redirect_to #book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: #book }
else
format.html { render :edit }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.json
def destroy
#book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
#book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:name, :author, :price)
end
end
`Rails.application.routes.draw do
resources :books
root :to => "home#index"
get 'home/index'
end`
You can restrict the restful routes to make edit and destroy actions inaccessible.
In your routes.rb,
resources :books, except: [:edit, :destroy]
See: http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
EDIT
If you want to keep to the RESTful routes (so that you don't have to modify code in your views), you can use before_action in controller to redirect users.
before_action :redirect_user, only: [:edit,:destroy]
def redirect_user
redirect_to root_path
end
This approach is generally used when you want to restrict access to certain actions based on some condition.
For example, if you want only admins to edit and remove books, you can have condition inside redirect_user that checks if current user is admin or not and redirects non-admin users.
You should look in to the cancancan gem.
https://github.com/CanCanCommunity/cancancan
It's an authorization library for Ruby on Rails which restricts what resources a given user is allowed to access. So you can create an admin class, and only allow administrators to edit and destroy. Its pretty simple to use and works well with devise.

Resources