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.
Related
I want to have a page that displays links to other websites in my project. I created links.html.erb in my customers views but when I try access the page I get this error.
ActiveRecord::RecordNotFound in CustomersController#show
Couldn't find Customer with 'id'=links
Customers Controller:
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /customers
# GET /customers.json
def index
#customers = Customer.all
#q = Tour.search(params[:q])
#tours = #q.result.page(params[:page]).per(5)
#q.build_condition if #q.conditions.empty?
#q.build_sort if #q.sorts.empty?
end
def links
end
# GET /customers/1
# GET /customers/1.json
def show
#customers = Customer.all
end
def welcome
end
# GET /customers/new
def new
#customer = Customer.new
end
# GET /customers/1/edit
def edit
end
# POST /customers
# POST /customers.json
def create
#customer = Customer.new(customer_params)
respond_to do |format|
if #customer.save
format.html { redirect_to #customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: #customer }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /customers/1
# PATCH/PUT /customers/1.json
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /customers/1
# DELETE /customers/1.json
def destroy
#customer.destroy
respond_to do |format|
format.html { redirect_to customers_url, notice: 'Customer record successfully deleted' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
#customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:name, :address, :telephone_no, :ticket_number)
end
end
Routes:
Rails.application.routes.draw do
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :customers
resources :tours
devise_for :users
root 'customers#welcome'
In view:
<% if current_user.customer? %>
<div class="col-sm-4">
<%= link_to image_tag("image1.jpg", size: "300x300"), {:controller => 'customers', :action => "links" } %>
<h3>Links</H3>
</div>
<% end %>
Anyone help with what is wrong here? Thanks.
Add get 'links' => 'customers#links', as: :link to the routes.rb and update your link as:
<%= link_to image_tag("image1.jpg", size: "300x300"), link_path %>
Here's a bit of an expansion on Ganesh's answer.
When you do this:
<%= link_to image_tag("image1.jpg", size: "300x300"), {:controller => 'customers', :action => "links" } %>
You're creating a url to:
customers/links
In your routes, the first match for customers/links is customers/:id which routes to customers/show with params[:id] = 'links'. See the Guide if you don't understand why this is true. That's why you're getting the error:
ActiveRecord::RecordNotFound in CustomersController#show
Couldn't find Customer with 'id'=links
As Ganesh correctly points out, you can coerce the routes exactly as he says. To me, it is a little smelly to put this links page in the CustomerController and to coerce the routes. But, that's really a design decision based on the problem(s) you're trying to solve.
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
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...
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.
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