No route matches while creating nested resource in Rails - ruby-on-rails

I am trying to create a new teacher for a specific school in my project and I got this error:
No route matches [POST] "/schools/3/teachers/new"
Here is my teachers_controller.rb:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def create
#teacher = Teacher.new(teacher_params)
#teacher.save
redirect_to school_path(school)
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
end
schools_controller.rb:
class SchoolsController < ApplicationController
def show
#school = School.find(params[:id])
end
def new
#school = School.new
end
def edit
#school = School.find(params[:id])
end
def update
#school = School.find(params[:id])
if #school.update(school_params)
redirect_to #school
else
render 'edit'
end
end
def index
#schools = School.all
end
def create
#school = School.new(school_params)
if #school.save
redirect_to schools_path
else
render 'new'
end
end
def destroy
#school = School.find(params[:id])
#school.destroy
redirect_to schools_path
end
private
def school_params
params.require(:school).permit(:name)
end
end
routes.rb:
Rails.application.routes.draw do
resources :schools do
resources :teachers
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'welcome#index'
And teachers/new.html.erb:
<%= form_for :teacher, url: school_teachers_path(school) do |f| %>
<p>
<%= f.label :firstName %><br>
<%= f.text_field :firstName %>
</p>
<p>
<%= f.label :lastName %><br>
<%= f.text_field :lastName %>
</p>
<p>
<%= f.label :middleName %><br>
<%= f.text_field :middleName %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>

As your teacher resource is nested under the school resource, so you need to pass the school when you try to create a teacher.
Try changing your new and create actions in teachers_controller.rb to something like this:
def new
#school = School.find(params[:school_id])
#teacher = #school.teachers.build
end
def create
#school = School.find(params[:school_id])
#teacher = #school.teachers.build(params[:teacher])
#teacher.save
redirect_to school_path(#school)
end
And, then change your form to this:
<%= form_for([#school, #teacher]) do %>
. . .
. . .
<% end %>

Try this in your form:
<%= form_for [school, Teacher.new] do |f| %>
The path you are posting to is for the index of teachers at a school:
school_teachers GET /schools/:school_id/teachers(.:format) teachers#index

I believe that it's a has_many belongs_to association. So you need to first change your teacher controller create action and new action.
class TeachersController < ApplicationController
def new
get_school
#teacher = #school.teachers.build
end
def create
get_school
#teacher = #school.teachers.build(teacher_params)
If #teacher.save
redirect_to school_path(school)
else
render 'new'
end
private
def teacher_params
params.require(:teacher).permit(:firstName, :lastName, :middleName)
end
def get_school
#school = School.find (params [:school_id])
end
end
Then in your form you 'll do :
<%= form_for([#school,#teacher]) do |f| %>
Hope this will help

Related

How can I create a form without using resources (action :new, :create) in Rails?

This is my controller
class SchoolsController < ApplicationController
def teacher
#teacher = Teacher.new
end
def form_create
#teacher = Teacher.new(teacher_params)
if teacher.save
redirect_to schools_teacher_path
else
flash[:notice] = "error"
end
end
private
def teacher_params
params.require(:teacher).permit(:name)
end
end
This is my views/schools/teacher.html.erb
<%= form_for :teacher do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
I am new to Ruby on Rails, and not sure how to proceed.
You should move this to a TeachersController let me show you how:
First you need to create the controller, you can get this done by typing this on the terminal at the project root directory:
$ rails g controller teachers new
Then into your route file (config/routes.rb):
resources :teachers, only: [:new, :create]
After that go to the teachers_controller.rb file and add the following:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def reate
#teacher = Teacher.new(teacher_params)
if #teacher.save
redirect_to schools_teacher_path
else
redirect_to schools_teacher_path, notice: "error"
end
end
private
def teacher_params
params.require(:teacher).permit(:name)
end
end
Then you can have the form at views/teachers/new.html.erb:
<%= form_for :teacher do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Please let me know how it goes!

Build a second step of a nested form?

I try to build a nested form with two bearing (= post do push do reviews)
And I have this error :
Error generated
I would like to know if I have the good practices to succeed this creation ?
My code
Views/pushs/show:
<%= link_to 'Add comment', new_post_push_review_path(#push.post_id, #push) %>
Reviews/controller :
class ReviewsController < ApplicationController
before_action :authenticate_user!
before_action :find_post
before_action :find_push
def new
#review = Review.new
end
def create
#review = #post.push.reviews.create(review_params)
#review.post_id = #push.post_id
#review.push_id = #push.id
#review.user_id = current_user.id
if #review.save
redirect_to push_path(#push.post_id, #push)
else
render 'new'
end
end
private
def review_params
params.require(:review).permit(:rating, :comment)
end
def find_post
#post = Post.find(params[:post_id])
end
def find_push
#post = Post.find(params[:post_id])
#push = Push.find(params[:push_id])
end
end
Views/reviews/new:
<%= simple_form_for([#post, #post.push.reviews.build]) do |f| %>
<%= f.input :rating %>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
& the routes :
resources :posts do
resources :pushs do
resources :reviews
end
end

action create couldn't be found for PostsController

I'm following a rails tutorial and need some help to proceed further. Problem is, once I fill out the form which has a title,body fields and hit submit, it has to redirect to the show.html.erb page instead it throws an error.
Error: The action 'create' could not be found for PostsController
routes.rb
Rails.application.routes.draw do
get "/pages/about" => "pages#about"
get "/pages/contact" => "pages#contact"
get "/posts" => "posts#index"
post "/posts" => "posts#create"
get "/posts/show" => "posts#show", as: :show
get "/posts/new" => "posts#new"
end
posts_controller_tests.rb
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
def index
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to show_path
end
def show
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
new.html.erb
<h1>Create a new blog post</h1>
<div class="form">
<%= form_for Post.new do |f| %>
<%= f.label :title %>: <br>
<%= f.text_field :title %> <br> <br>
<%= f.label :body %>: <br>
<%= f.text_area :body %> <br> <br>
<%= f.submit %>
<% end %>
</div>
Any help on this would be appreciated.
Note: You are using posts_controller_tests.rb not posts_controller.rb. You are putting your controller code in test controller.
Try to move the code in app/controllers/posts_controller.rb:
class PostsController < ApplicationController
def index
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to show_path
end
def show
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
Your create action always redirects you to the show action. It doesn't matter if your model was saved or not.
You have to check if the model was saved or not:
def create
#post = Post.new(post_params)
if #post.save
flash[:success] = 'Successfully saved'
redirect_to #post
else
render 'new'
end
end
If it wasn't saved, it renders the new action again.
Change your routes.rb to this:
Rails.application.routes.draw do
get "/pages/about" => "pages#about"
get "/pages/contact" => "pages#contact"
resources :posts
end
Moreover you should inherit your controller from ActionController::Base
so change first line of your controller to
class PostsController < ActionController::Base
and move the controller to app/controllers/posts_controller.rb

Rails - Updating and deleting content?

EDIT: I managed to delete! i had to define teh instance variable #movies = Movie.find(params[:id]) to the delete method in the controller.
I still can't update though. I get "param is missing or the value is empty: movie"
I forgot to add my contrller! sorry!
I'm trying to replicate one of my in class exercises into another app, for practice.
The idea is to be able to add new movies into a database, and get the option to update their info, and delete them as well. I can add new content, but I can't update them or delete them.
Appreciate any inputs I can get.
Routes.rb
Rails.application.routes.draw do
root "movies#index"
get "/movies", to: "movies#index"
get "/movies/new", to: "movies#new", as: "new_movie"
get '/movies/:id', to: "movies#movie_page", as: "movie_page"
post "/movies", to: "movies#add"
get "/movies/:id/edit", to: "movies#edit", as: "movie_edit"
put "/movies/:id", to: "movies#update"
patch "/movies/:id", to: "movies#update", as: "update_movie"
delete "/movies/:id", to: "movies#delete", as: "delete_movie"
end
Controller
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
def movie_page
#movies = Movie.find(params[:id])
end
def new
#movies = Movie.new
end
def add
#movies = Movie.create(movie_params)
redirect_to movies_path
end
def edit
#movies = Movie.find(params[:id])
end
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def delete
#movies = Movie.find(params[:id])
#movies.destroy
# flash[:notice] = "Shirt was deleted."
redirect_to root_path, notice: "Shirt was deleted."
end
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
# def set_movie
# #movies = Movie.find(params[:id])
# end
end
Form partial
<%= form_for #movies do |m| %>
<p>
<%= m.label :title %><br>
<%= m.text_field :title %>
</p>
<p>
<%= m.label :description %><br>
<%= m.text_field :description %>
</p>
<p>
<%= m.label :year_released %><br>
<%= m.text_field :year_released %>
</p>
<p>
<%= m.submit %>
</p>
<% end %>
Movie page html (individual movies, labeled by IDs)**I can't update or Delete, no route matches Delete.
When I press Update - I get param is missing or the value is empty: movie
<h1><%= #movies.title %></h1>
<h2>Released on : <%= #movies.year_released %> </h2>
<p> <%= #movies.description %> </p>
<%= link_to "Update", movie_edit_path(#movies) %>
<%= link_to "Delete", movies_path, method: :delete %
Edit page *I cant access this link. the form is the problem
<h1>Edit <%= #movies.title %> Info </h1>
<%= render "form" %>
<%= link_to "Cancel Edit", movie_edit_path(#movies) %>
Many thanks guys
def update
#movie = Move.find(params[:id])
#movie.update(movie_params)
redirect_to movie_path(#movie)
end
on your routes. all you need is resources :movies
you are getting param is empty because you have to pass in the id of the movie to update.
The major issue is that you do not load the variable #movies from the DB before you use it.
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def update
#movies.find(params[:id])
#movie.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
Aside from that you have tons of duplication and quite a few idiosyncrasies.
Rails uses these naming conventions for actions:
index
show (not movie_page)
new
create (not add)
edit
update
destroy (not delete)
You should follow them unless you have a damn good reason not to.
class MoviesController < ApplicationController
# cuts the duplication
before_filter :set_movie, except: [:new, :index]
def index
#movies = Movie.all
end
# GET /movies/:id
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# POST /movies
def create
#movie = Movie.create(movie_params)
redirect_to movies_path
end
# GET /movies/edit
def edit
end
# PUT|PATCH /movies/:id
def update
#movie.update(movie_params)
redirect_to #movie, notice: "Shirt was updated."
end
# DELETE /movies/:id
def destroy
#movie.destroy
redirect_to action: :index
end
private
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
def set_movie
# Use the singular form when naming a variable with a single record
# failure to do so may result in tarring and feathering
#movie = Movie.find(params[:id])
end
end

collection_select doesn't save through form

I know there is a lot of similar posts where people have the same problem, but none of them helped me. If i create new article then it won't have a category. But if i edit article created earlier in seed.rb then the category is updated.
What's wrong?
Categories table:
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.timestamps
end
end
end
category.rb
class Category < ActiveRecord::Base
has_many :articles
end
article.rb
class Article < ActiveRecord::Base
belongs_to :category
end
and then i have a _form file
<%= form_for(#article) do |f| %>
<div class="title">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="content">
<%= f.label :content %>
<%= f.text_field :content %>
</div>
<div class="category">
<%= f.label :category %>
<%= collection_select(:article, :category_id, Category.all, :id, :name) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
There is a categories_controller file:
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def show
#category = Category.find(params[:id])
#articles = #category.articles
end
def new
#category = Category.new
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to(:action => 'index')
else
render('new')
end
end
def edit
#category = Category.find(params[:id])
end
def update
#category = Category.find(params[:id])
if #category.update_attributes(category_params)
redirect_to(:action => 'show', :id => #category.id)
else
render('index')
end
end
def delete
#category = Category.find(params[:id])
end
def destroy
Category.find(params[:id]).destroy
redirect_to(:action => 'index')
end
private
def category_params
params.require(:category).permit(:name)
end
end
Articles controller file:
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to(:action => 'index')
else
render('new')
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update_attributes(article_params)
redirect_to(:action => 'show', :id => #article.id)
else
render('index')
end
end
def delete
#article = Article.find(params[:id])
end
def destroy
Article.find(params[:id]).destroy
redirect_to(:action => 'index')
end
private
def article_params
params.require(:article).permit(:title, :content)
end
end
It looks like you're not building the association in the articles#create action. The category_id is being sent through your form, but you still need to to build the Active Record association. You could try something like this in the articles controller:
def create
#article = Article.new(article_params)
#category = Category.find(params[:category_id])
#article.category = #category
if #article.save
redirect_to(:action => 'index')
else
render('new')
end
end
Keep in mind, there are multiple ways to create an association. Your Article class has the following five methods to manipulate the association:
#article.category
#article.category=
#article.build_category
#article.create_category
#article.create_category!

Resources