NoMethodError in PostsController#create undefined method `body' - ruby-on-rails

Whenever I try to save the post, this error is showing up.
Here's my new.html.erb file.
<div id="page_wrapper">
<h1>New Post</h1>
<%= form_for :post, url: posts_path do |f| %>
<% if #post.errors.any? %>
<div id="errors">
<h2><%= pluralize(#post.errors.count, "error") %> prevented this post from saving:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
</p>
<p>
<%= f.label :date %><br>
<%= f.text_field :date %><br>
</p>
<p>
<%= f.label :time %><br>
<%= f.text_field :time %><br>
</p>
<p>
<%= f.label :location %><br>
<%= f.text_field :location %><br>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
</div>
Here's my show.html.erb file.
<div id="page_wrapper">
<h1 class="title">
<%= #post.title %>
</h1>
<p class="date">
Submitted <%= time_ago_in_words(#post.created_at) %> Ago
</p>
<p class="time">
<%= #post.time %>
</p>
<p class="location">
<%= #post.location %>
</p>
</div>
Here's my posts_controller.rb file.
class PostsController < ApplicationController
def index
#posts = Post.all.order('created_at DESC')
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :body, :location)
end
end
Hers's my routes.rb file
Rails.application.routes.draw do
resources :posts
root "posts#index"
end

You have added a validation for body in your post.rb. But you don't have the field body in your posts table.
So, when #post.create is invoked, all the validations defined in post.rb are run and since you don't have a body field, you were getting an Undefined method 'body' for Post error.
To solve it, remove the validation for body in post.rb
Remove the following line
validates :body, presence: true
And you should be good to go.

params.require(:post).permit(:title, :body, :location)
You required :body but in your form you have title, date, time and location.
Remove it and make sure you have this attributes in your strong params like this:
params.require(:post).permit(:title, :date, :time, :location)

Related

Rails - create and update action don't work

I'm a beginner in Rails, I have a Suplement controller and I can't create or edit a suplement (delete works fine). I'm not getting any errors, just nothing happens when I click and everything's working fine from the console. I tried everything I know (which is not much) and I couldn't find a question like this, similar answers didn't help. I'd appreciate any help, thanks!
class SuplementsController < ApplicationController
before_action :set_suplement, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#suplement = Suplement.all.order("created_at DESC")
end
def new
#suplement = Suplement.new
end
def create
#suplement = Suplement.new(suplement_params)
if #suplement.save
redirect_to '/suplements'
else
render '/suplements/new'
end
end
def show
end
def edit
end
def update
if #suplement.update(suplement_params)
redirect_to '/suplements'
else
redirect_to '/suplements/new'
end
end
def destroy
#suplement.destroy
redirect_to '/suplements'
end
private
def set_suplement
#suplement = Suplement.find(params[:id])
end
def suplement_params
params.require(:suplement).permit(:name,
:number_of_units,
:daily_dosage_in_units,
:number_of_days,
:suplement_cost
)
end
end
Here's a view:
<h1>Create new suplement</h1>
<%= form_for(#suplement) do |f| %>
<%= render 'form', suplement: #suplement %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and here's a form partial:
<%= form_for(#suplement) do |f| %>
<% if #suplement.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#suplement.errors.count, "error") %> prohibited this suplement from being saved:</h2>
<ul>
<% #suplement.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :number_of_units %>
<%= f.text_field :number_of_units %>
</div>
<div class="field">
<%= f.label :daily_dosage_in_units %>
<%= f.text_area :daily_dosage_in_units %>
</div>
<div class="field">
<%= f.label :number_of_days %>
<%= f.text_area :number_of_days %>
</div>
<div class="field">
<%= f.label :suplement_cost %>
<%= f.text_area :suplement_cost %>
</div>
<% end %>
Also my models:
class Suplement < ApplicationRecord
belongs_to :user
validates :name,
:number_of_units,
:daily_dosage_in_units,
:number_of_days,
:suplement_cost,
presence: true
end
and
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :suplements
end
It looks like the problem is that you have 2 forms.
Uou have a form_for #suplement in your _form.html.erb file and also in your new.html.erb file. Try removing it from new.html.erb so your file looks like this
new.html.erb
<h1>Create new suplement</h1>
<%= render 'form', suplement: #suplement %>
_form.html.erb
<%= form_for(#suplement) do |f| %>
<% if #suplement.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#suplement.errors.count, "error") %> prohibited this suplement from being saved:</h2>
<ul>
<% #suplement.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :number_of_units %>
<%= f.text_field :number_of_units %>
</div>
<div class="field">
<%= f.label :daily_dosage_in_units %>
<%= f.text_area :daily_dosage_in_units %>
</div>
<div class="field">
<%= f.label :number_of_days %>
<%= f.text_area :number_of_days %>
</div>
<div class="field">
<%= f.label :suplement_cost %>
<%= f.text_area :suplement_cost %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
What I did is:
1) Deleted form_for and submit button inside new.html.erb
2) Added submit button in _form.html.erb, so the variable f is accessible
Also, since you are passing a variable #suplement to partial local variable suplement, you can use the variable suplement inside _form.html.erb file without the # sign
EDIT (Regarding comment):
Your getting User presence validation Error, because from Rails 5.0, belongs_to associations are automatically validated for presence.
If you do not need a user in your suplement object all the time then you should change your association to belongs_to :user, optional: true
OR
if you do need the user, and you always want it to be the current user logged in, then add this to your _form
<%=f.hidden_field :user_id, current_user.id %>
This will use Devise helper method to get the current logged in user and assign it to this hidden field. Don't forget to add this parameter in your controler suplement_params controller method
In the #edit of your controller, you need to set the value of the #suplement variable.
def edit
#suplement = Suplement.find(params[:id])
end
you should also include the above line as the first line in your #update method
def update
#suplement = Suplement.find(params[:id])
if #suplement.update_attributes(suplement_params)
# continued...
end

Rails - Couldn't find Student with 'id'=

I'm getting the error above when I try to create a a 'mark' for a 'student'. I can't figure out how to pass the :student_id when I create a new mark.
Routes
Rails.application.routes.draw do
resources :students do
resources :marks
end
resources :marks
root 'students#index'
Marks Controller
class MarksController < ApplicationController
def create
#student = Student.find(params[:student_id])
#mark = #student.marks.create(params[:input1, :input2, :input3, :weight1, :weight2, :weight3, :mark1, :mark2, :mark3, :final_mark].permit(:input1, :input2, :input3, :weight1, :weight2, :weight3, :mark1, :mark2, :mark3, :final_mark))
#mark.save
if #mark.save
redirect_to student_path(#student)
else
render 'new'
end
end
def new
#mark = Mark.new
end
private
def set_mark
#mark = Mark.find(params[:id])
end
end
Students Show View
<p id="notice"><%= notice %></p>
<p>
<strong>Student Number</strong>
<%= #student.StudentNumber %>
</p>
<p>
<strong>Project Title</strong>
<%= #student.ProjectTitle %>
</p>
<p>
<strong>Project PDF</strong>
<%= #student.ProjectTitle %>
</p>
<p>
<strong>Reader 1</strong>
<%= #student.Reader1 %>
</p>
<p>
<strong>Reader 2</strong>
<%= #student.Reader2 %>
</p>
<h3> <%= link_to 'Add Mark', new_student_mark_path(#student), class:"btn btn-warning"%> </h3>
<p>
<strong>Reader 3</strong>
<%= #student.Reader3 %>
</p>
<%= link_to 'Edit', edit_student_path(#student) %> |
<%= link_to 'Back', students_path %>
Marks Form
<%= form_for #mark, html: {multipart: true} do |f| %>
<% if #mark.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#mark.errors.count, "error") %> prohibited this grading from being saved:</h2>
<ul>
<% #mark.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label 'Introduction' %><br>
<%= f.text_area :input1 %>
<%= f.number_field :weight1 %>
<%= f.number_field :mark1 %>
</div>
<div class="field">
<%= f.label 'Main' %><br>
<%= f.text_area :input2 %>
<%= f.number_field :weight2 %>
<%= f.number_field :mark2 %>
</div>
<div class="field">
<%= f.label 'Conclusion' %><br>
<%= f.text_area :input3 %>
<%= f.number_field :weight3 %>
<%= f.number_field :mark3 %>
</div>
<div class="actions">
<%= f.submit class:"btn-xs btn-success"%>
</div>
<% end %>
Mark model
class Mark < ActiveRecord::Base
belongs_to :student
end
Student Model
class Student < ActiveRecord::Base
has_many :marks
has_attached_file :document
validates_attachment :document, :content_type => { :content_type => %w(application/pdf) }
end
It's probably something really stupid but if anyone could explain the problem I'd be really grateful.
Thanks
I don't suggest you using hidden fields for this purpose.
You should pass student together with mark into form_for helper and rails will generate proper url for you which will look like: /students/:student_id/marks
In this case it will be possible to extract student_id from params in your action later.
form_for [#student, #mark], html: {multipart: true} do |f|
More information about nested resources:
http://guides.rubyonrails.org/routing.html#nested-resources
http://www.informit.com/articles/article.aspx?p=1671632&seqNum=7
https://gist.github.com/jhjguxin/3074080
UPDATE:
Forgot to mention that in order to make this work you need to pass student instance into your template at new action:
def new
#student = Student.find(params[:student_id])
#mark = #student.marks.build
end

Getting "param is missing or the value is empty: post" explained below

when i click new post and try to save a new post it gives me that error, then i go to the controller :
private
def posts_params
params.require(:post).permit(:title, :description)
end
and change 'require(:post)' to 'require(:posts' then i works
but then i try to edit the new post i just created and when i click to save it it gives me the same error, then i just change it back to 'required(:post)' and it works, why this is happening ? it's like a loop, if one works the other doesn't and to work i have to change that one thing
Controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def edit
#posts = Post.find(params[:id])
end
def update
#posts = Post.find(params[:id])
if #posts.update(posts_params)
redirect_to #posts
else
render 'edit'
end
end
def new
#posts = Post.new
end
def create
#posts = Post.new(posts_params)
if #posts.save
redirect_to #posts
else
render 'new'
end
end
def show
#posts = Post.find(params[:id])
end
private
def posts_params
params.require(:post).permit(:title, :description)
end
end
view edit:
<h1>Editing post</h1>
<%= form_for(#posts) do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
view new:
<h1>New Article</h1>
<%= form_for :posts, url: posts_path do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
can someone point the problem out ?
You are mixing
form_for(#posts) do |f|
and
form_for :posts, url: posts_path
In your forms.
the :posts version will generate params[:posts] and the #posts version will generate params[:post]. Hence the issue you are seeing. Make sure you posts_params is as follows.
def posts_params
params.require(:post).permit(:title, :description)
end
then just change both of your forms to be
<%= form_for(#posts) do |f| %>
rails will figure out which to call automatically for you, so you will not have to specify the paths..
On a side note, I would probably change #posts to be #post everywhere but the index action, just so that it makes more sense, Since in new,edit,etc.. you are dealing with a singular post.
Since rails is looking at the Model/class of the variable when generating the routes (When given an instance variable) the name of the variable doesn't matter to the framework, but makes it easier (in my opinion) for the programmer to understand

I receive an error that "No Route Matches" {...id=>nil} *Wicked*

I have seen a lot of similar routing issues and id=>nil posts, but none of the solutions have resolved my error.
First here is the entire error:
ActionController::UrlGenerationError in ProfileSteps#personal
Showing ...profile_steps/personal.html.erb where line #1 raised:
No route matches {:action=>"show", :controller=>"profile_steps", :id=>nil
I am using Wicked to create a multi step form and it seems like the I am not fetching the :id properly.
Here is the profiles_controller.rb following 'signup' and creating the 1st step of profile
def create
#profile = Profile.new(profile_params[:profile])
if #profile.save
session[:profile_id] = #profile.id
redirect_to profile_steps_path
else
render :new
end
end
Here is the profile_steps_controller.rb which is the next step of form it is redirected to
class ProfileStepsController < ApplicationController
include Wicked::Wizard
steps :personal
def show
#profile = Profile.new(params[:profile])
session[:profile_id] = #profile.id
render_wizard
end
def update
#profile = Profile.new(profile_params)
#profile.attributes = (profile_params)
render_wizard #profile
end
private
def profile_params
params.require(:profile).permit(:description, :name, :website)
end
def redirect_to_finish_wizard
redirect_to root_url, notice: "Thank you for signing up."
end
end
views/profile_steps/personal.html.erb
<%= form_for #profile, url: wizard_path do |f| %>
<br>
<div class="field">
<%= f.label :name, "Company Name" %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :website %><br>
<%= f.text_field :website %>
</div>
<br>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<br>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
routes.rb
project::Application.routes.draw do
resources :profiles
resources :profile_steps
devise_for :users, :controllers => { :registrations => "registrations" }
root "pages#home"
get "profile" => "pages#profile"
match "profile_steps/personal", to: "profile_steps#personal", via: "post"
Thanks in advance and my apologies if this has been addressed in previous posts.
Updated:
Here is the 1st page of the multistep form:
new.html.erb
<%= form_for(#profile) do |f| %>
<% if #profile.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#profile.errors.count, "error") %> prohibited this profile from being saved:</h2>
<ul>
<% #profile.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<h1>New profile</h1>
<div>
<%= f.radio_button ..., true %> <%= f.label ... %>
</div>
<div>
<%= f.radio_button ..., false %> <%= f.label ... %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I had this problem in the view on the first page of the wizard, I solved it using a helper method:
def safe_previous_wizard_path(id)
id ? previous_wizard_path : root_path
end
or even:
<% if applicant.persisted? %>
Back
<% end %>

Ruby on Rails, instead of update make new entry to model

I made a simple demo site, with an model for the patients name (name:string) and another model with the treatment (content:text). I created this "project" to learn more about the accepts_nested_attribute for tag and the fields_for tag.
Now my problem is that on the patient show page i created an nested formula for the treatment , like you can see here:
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #patient.name %>
</p>
<ol>
<% for treatment in #patient.treatments %>
<li><%= treatment.content %></li>
<% end %>
</ol>
<%= form_for(#patient) do |f| %>
<%= f.fields_for :treatments do |builder| %>
<div class="field">
<%= builder.label :content %><br />
<%= builder.text_field :content %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<%= link_to 'Edit', edit_patient_path(#patient) %> |
<%= link_to 'Back', patients_path %>
So my problem is that in the builder.text_field :content better called the input shows up the last saved treatment from <%= builder.content %>, but i want that he does not update it instead i want to add new treatments! Hopefully somebody understands me! Thanks
I would create separate controller for creating only the treatment, eg.
# treatments_controller.rb
class TreatmentsController < ApplicationController
def create
#patient = Patient.find(params[:patient_id])
#treatment = #patient.treatments.new(params[:treatment])
if #treatment.save
redirect_to #patient
else
# handle unsuccessful treatment save
end
end
end
# routes.rb:
resources :patients do
resources :treatments, only: :create
end
# form:
<%= form_for #patient, #treatment do |f| %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_field :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You should also set #treatment variable in the patient#show action, like this:
#treatment = #patient.treatments.new

Resources