NoMethodError in Users#show (Ruby Rails) - ruby-on-rails

I'm running into a NoMethodError in my Users#show when trying to include a form partial for submitting a task item (_form.html.erb). My other partial (_item.html.erb) is rendering properly. My item model and my user model are related to each other, user has_many :items, and item belongs_to :user.
Any and all help would be greatly appreciated!
Below is my routes.rb
Rails.application.routes.draw do
get 'welcome/index'
get 'welcome/about'
root 'users#show'
resources :users do
resources :items, only: [:new, :create]
end
devise_for :users
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Below is my terminal output
ActionView::Template::Error (undefined method `items_path' for #<#<Class:0x007fefeca61dd0>:0x007fefeca58b18>
Did you mean? items_create_path):
1: <h4> Create a new to-do item </h4>
2:
3: <%= form_for #item do |f| %>
4: <%= f.label :name %>
5: <%= f.text_field :name, class: 'form-control', placeholder: "Enter task here" %>
Items Controller
class ItemsController < ApplicationController
def new
#item = Item.new
end
def create
#item = Item.new
#item.user = current_user
#item.name = params[:item][:name]
if #item.save
flash[:notice] = "Item saved"
redirect_to #item
else
flash.now[:alert] = "Item was not created, please try again."
render :new
end
end
end
Users Controller
class UsersController < ApplicationController
def show
if !current_user.nil?
#user = current_user
#item = Item.new
#items = #user.items
else
redirect_to new_user_registration_path
end
end
end
Users#show page
<h2> Your to-do list</h2>
<div class="col-md-8">
<div class='items'>
<%= render partial: "items/item", local: { item: #item} %>
</div>
</div>
<div class="col-md-8">
<div class='new-item'>
<%= render partial: "items/form", local: { item: #item } %>
</div>
</div>

In your routes.rb file, you have items defined as a nested resource. You can check all of your routes by running this command on your terminal: rake routes.
For your routes specifically, you say:
resources :users do
resources :items, only: [:new, :create]
end
This would give you routes for GET /users/:user_id/items/new and POST /users/:user_id/items. However, in your form, it looks like you're trying to do this: <%= form_for #item do |f| %>. You don't have a route defined for an item by itself. You'll need to supply a user as well.
Try this for your form:
<%= form_for [#user, #item] do |f| %>
And something like this in your ItemsController:
class ItemsController
def new
#user = current_user
#item = Item.new
end
end

Your items route is nested under users. therefore you have to pass both to the form_for - a user and an item.
Something like this will probably work:
<%= form_for(current_user, #item) do |f| %>

Related

"form_with cannot find the Post model"

I am trying to create the form on my "new" page. I am using form_with. I have already checked my routes, controllers and views, but I have not yet identified the problem.
The error that is returning is:
NameError in Pages # new
undefined local variable or method `post 'for # <# <Class: 0x00007f5640e1f440>: 0x00007f5640e1c060>
Did you mean? #post
Extracted source (around line # 5):
<% = form_with (model: post, location: true) do | form | %>
<div class = "form-group">
<% = form.label: title%>
Below is my form using form_with:
<h1> CREATE NEW ARTICLE </h1>
<% = form_with (model: post, location: true) do | form | %>
<div class = "form-group">
<% = form.label: title%>
<% = form.text_field: title, class: 'form-control'%>
</div>
<div class = "form-group">
<% = form.label: author%>
<% = form.text_field: author, class: 'form-control'%>
</div>
<div class = "form-group">
<% = form.label: body%>
<% = form.text_area: body, class: 'form-control', rows: 10%>
</div>
<% = form.submit class: 'btn btn-primary', data: {disable_with: 'Creating ..'}%>
<% end%>
this is my controller:
class PagesController <ApplicationController
def articles
#posts = Post.all
end
def new
#post = Post.new
end
def show
#post = Post.find (params [: id])
end
def create
#post = # Post.new (post_params)
# post.save
redirect_to article_path (#post)
end
private
def post_params
params.require (: post) .permit (: title,: author,: body)
end
end
Now here are my routes:
Rails.application.routes.draw do
root 'pages # index'
get 'articles', to: 'pages # articles'
get 'articles / new', to: 'pages # new'
get 'articles /: id', to: 'pages # show', as: 'article'
post 'articles', to: 'pages # create'
end
Replace
<% = form_with(model: post, location: true) do | form | %>
.....
<% end %>
with
<% = form_with(model: post, local: true) do | form | %>
....
<% end %>
and new.html.erb should contains
<%= render 'form', post: #post` %>
And update your controller with posts_controller.rb
class PostsController < ApplicationController
before_action :find_post, only: [:show]
def index
#posts = Post.all
end
def new
#post = Post.new
end
def show
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :author, :body)
end
end
Routes should be as
get 'posts', to: 'posts#index'
get 'posts/new', to: 'posts#new'
get 'posts/:id', to: 'posts#show'
post 'posts', to: 'posts#create'
or simply as
resources :posts, only: [:index, :new, :show, :create]
There's quite a lot of whitespace issues going on in your code snippets, but I think that might be a side effect of however you've copied the code rather than any deliberate cause.
The error you're seeing is because the form_with method doesn't know what post is. In your controller, you set up #post in your new method, which means that new.html.erb will be able to see the instance variable #post, but it won't know what post (without the #) is.
So if the form is in new.html.erb, you'd need to use #post in place of post here.
That said, common Rails behaviour is to have the form in its own partial _form.html.erb. That might be the case here (you don't specify the file names of your views). In that case, you can tell the partial to use local variables rather than the instance variable that the main template file uses.
To do that, you need to map an instance variable to a local one in the render call to your form, for example:
# in new.html.erb
<%= render 'form', post: #post` %>
This is saying 'take the object that I can see as #post, and make it available as the post local variable within the form template'.

How to modify tables of a model (without controller) from another controller?

So I have a model GeneralCourses that I want to update from a controller Courses. I want to be able to add and edit entries in the model GenralCourses.
The issue I am having now is that when I want to submit the form it tells me:
No route matches [POST] "/courses/create"
courses_controller:
class CoursesController < ApplicationController
def new
#course = GeneralCourse.new
end
def create
#course = GeneralCourse.new(contact_params)
if #course.save
flash[:success] = "Course created"
redirect_to new_course_path
else
flash[:danger] = "Announcement not uploaded"
redirect_to new_course_path
end
end
def update
end
private
def contact_params
params.require(:general_course).permit(:course_code, :course_title, :course_unit, :course_desc)
end
end
courses form:
<%= form_for '/courses/create', method: :POST do |f| %>
with the form fields
<%= end %>
routes.rb:
Rails.application.routes.draw do
devise_for :admins
devise_for :staffs
devise_for :students
resources :courses
resources :announcements
resources :school_calenders
resources :pages
get '/stud/timetable' => 'pages#timetable'
get '/login' => 'pages#login'
get '/stud/announcement' => 'pages#ann'
root 'pages#home'
end
Given that it looks like you're using conventional routes for courses, you should be able to do:
<%= form_for courses_path do |f| %>
... with the form fields
<% end %>
Now, given also that in your new action, you did:
def new
#course = GeneralCourse.new
end
Then you really ought to be able to do:
<%= form_for #course do |f| %>
... with the form fields
<% end %>
Now, if you make your form into a partial, you should be able to use the same partial for your new action and your edit action.

Undefined method build in rails 4 has_many association

I have the following set up in rails:
Document has_many Sections
Section belongs_to Document
The Section form is completed in the documents/show view...the Document controller for this action is:
def show
#document = current_user.documents.find(params[:id])
#section = Section.new if logged_in?
end
The Section form in documents/show is as follows:
<%= form_for(#section) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new section..." %>
</div>
<%= hidden_field_tag :document_id, #document.id %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
Where you can see a hidden_field_tag is sending the document_id
The sections_controller is as follows:
class SectionsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy, :show, :index]
def create
#document = Document.find(params[:document_id])
#section = #document.build(section_params)
if #section.save
flash[:success] = "Section created!"
redirect_to user_path(current_user)
else
render 'static_pages/home'
end
end
def destroy
end
def index
end
private
def section_params
params.require(:section).permit(:content)
end
end
I get the following error which I have not been able to resolve.
**NoMethodError (undefined method `build' for #<Document:0x00000004e48640>):
app/controllers/sections_controller.rb:6:in `create'**
I am sure it must be something simple I am overlooking but can't seem to find it. Any help would be appreciated:
Replace the below line :-
#section = #document.build(section_params)
with
#section = #document.sections.build(section_params)
You have a has_many associations named sections in the Document model. Thus as per the guide, you got the method collection.build(attributes = {}, ...). Read the section 4.3.1.14 collection.build(attributes = {}, ...) under the link I gave to you.

No route error for nested resources in Rails

Hi this is my first time using nested resources. I did rake routes and found a path to new_user_album_path, but it doesn't seem to work. Could the problem be because I did a double nest?
The problem is specifically when I click a link in my Users views file named show.html.erb . Trying to link to a "create an album" page but that's when it shows me an error:
No route matches {:action=>"new", :controller=>"albums"}
Here are my files:
show.html.erb
<% provide(:title, "Welcome, #{#user.name}!") %>
<div>
You currently have <%= pluralize(#user.albums.count, "album") %>
</div>
<div>
<%= link_to "Create a new album!", new_user_album_path %>
</div>
<div>
<% if #user.albums.any? %>
hey
<% else %>
boo
<% end %>
</div>
<%= link_to "Back", users_path %>
Config/routes
Pholder::Application.routes.draw do
resources :users do
resources :albums do
resources :pictures
end
end
Controller
class AlbumsController < ApplicationController
def index
#albums = Albums.all
respond_to do |format|
format.html
format.json { render json: #albums }
end
end
def new
#user = User.find(params[:user_id])
end
end
You need to pass the user to the route method, like:
new_user_album_path(#user)

ActiveRecord::RecordNotFound - Couldn't find Keynote without an ID

I'm building an application that has a Keynote model and a Story model (as well as a User model that I implemented with Devise).
Keynotes have many Stories and a Story belongs to a Keynote.
I'm having problems creating new stories and I get the following error:
ActiveRecord::RecordNotFound in StoriesController#create
Couldn't find Keynote without an ID
The error happens on line 17 of stories_controller.rb which is
#keynote = Keynote.find(params[:keynote_id])
in the create method.
This is part of my stories_controller.rb
class StoriesController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def index
#keynote = Keynote.find(params[:keynote_id])
#stories = #keynote.stories
end
def new
#keynote = Keynote.find(params[:keynote_id])
#story = #keynote.stories.build
end
def create
if user_signed_in?
#keynote = Keynote.find(params[:keynote_id])
#story = #keynote.current_user.stories.build(params[:story])
if #story.save
flash[:notice] = 'Question submission succeeded'
redirect_to keynote_stories_path
else
render :action => 'new'
end
end
end
This is my keynotes_controller.rb
class KeynotesController < ApplicationController
def index
#keynotes = Keynote.find :all, :order => 'id ASC'
end
def new
#keynote = Keynote.new
end
def show
#keynote = Keynote.find(params[:id])
end
def create
#keynote = Keynote.new(params[:keynote])
if #keynote.save
flash[:notice] = 'Keynote submission succeeded'
redirect_to keynotes_path
else
render :action => 'new'
end
end
end
Any help would be really appreciated.
Edit:
These are the Parameters when I try to create a new Story.
{"utf8"=>"✓",
"authenticity_token"=>"76odSpcfpTlnePxr+WBt36fVdiLD2z+Gnkxt/Eu1/TU=",
"story"=>{"name"=>"as"},
"commit"=>"Send"}
It looks like the ID for the Keynote is not being passed.
This is the view for StoriesController#new
<%= error_messages_for 'story' %>
<%= form_for #story do |f| %>
<p>
Question:<br />
<%= f.text_field :name %>
</p>
<p>
<%= submit_tag "Ask" %>
</p>
<% end %>
This is what I have in my routes.rb file:
get "keynotes/index"
get "users/show"
devise_for :users
get "votes/create"
get "stories/index"
resources :keynotes do
resources :stories
end
resources :stories do
get 'bin', :on => :collection
resources :votes
end
resources :users
root :to => 'keynotes#index'
I think this should do the trick:
<%= form_for #story do |f| %>
<%= hidden_field_tag 'keynote_id', #keynote.id %>
.
rest of the form stuff here
.
<% end %>
PS. Not sure if you will get the keynote_id in params[:keynote_id] or params[:story][:keynote_id] .. check out both.
NB: I think there would be a easier way to do it too, using fields_for or something similar, but I don't have access to a Rails setup at the moment to test that out.

Resources