NoMethodError in HealthReport#new - ruby-on-rails

I keep get this error when I want to render my form
The error is pointing the <%= form_for(#hreport) do |f| %>, I'm not sure where when wrong or i missed something, anyone help is appreciate!
<div class="col-md-6 col-md-offset-3">
<%= form_for(#hreports) do |f| %>
<%= f.label :"Student ID" %>
<%= f.text_field :studentid, class: 'form-control' %>
This is my health_report_controller.rb
class HealthReportController < ApplicationController
def index
#hreports = Healthreport.where(:user_id => current_user.id)
end
def new
#hreports = Healthreport.new
end
def create
#hreports = current_user.healthreports.build(hreport_params)
if #hreports.save
flash[:success] = "Report Submitted!"
else
end
end
def show
#hreports = Healthreport.find(params[:id])
end
private
def set_hreport
#hreport = Healthreport.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def hreport_params
params.require(:Healthreport).permit(:date, :studentid, :department, :issue)
end
end
This is my view
<% provide(:title, 'New Report') %>
<h1>Health and Safety Report</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#hreports) do |f| %>
<%= f.label :"Student ID" %>
<%= f.text_field :studentid, class: 'form-control' %>
<%= f.label :"Department of applicant" %>
<%= f.text_field :department, class: 'form-control' %>
<%= f.label :"Description of Issues" %>
<%= f.text_area :issue, placeholder: "Write your report here...", class: 'form-control' %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
This is my healthreport.rb inside model folder
class Healthreport < ApplicationRecord
belongs_to :user
end
This is my healthreport.rb inside db folder
class CreateHealthreports < ActiveRecord::Migration[5.0]
def change
create_table :healthreports do |t|
t.datetime :date
t.string :studentid
t.string :department
t.string :issue
t.timestamps
end
end
end
It's migration db file
class AddUserToHealthreport < ActiveRecord::Migration[5.0]
def change
add_reference :healthreports, :user, foreign_key: true
end
end

In your controller, you do this:
def new
#hreports = Healthreport.new
end
But in the view, you are expecting this
<%= form_for(#hreport) do |f| %>
You are passing #hreports but trying to use #hreport. Change the controller to be
def new
#hreport = Healthreport.new
end
(the index action should use the plural, the other actions should use the singular)
Two Rails convention/style things you should be aware of:
A singular variable name (such as #hreport) refers to a single object; a plural of that name (#hreports) refers to an array or an ActiveRecord relationship.
Model and Controller should use the same naming style: if the controller is named health_report_controller.rb and defines a HealthReportController, then the model file should be named health_report.rb and should define a HealthReport class.

Related

Why is my party not being created and saved to the database?

I have my parameters whitelisted and when I look at the output of party_params I see that they are permitted but when I got to save the instance into the database it gives me a rollback transaction in the console. I've tried just create, create then save, new then save. Is there something I am missing?
#controller
class PartiesController < ApplicationController
def new
#party = Party.new
end
def create
#party = Party.create(party_params)
redirect_to party_path(#party)
end
private
def party_params
params.require(:party).permit(
:name,
:trainer_id,
:pokemon1_id
)
end
end
#model
class Party < ApplicationRecord
belongs_to :trainer
belongs_to :pokemon
validates :name, presence: true
end
#view
<h1>Create a New Pokemon Party</h1>
<p>Select 6 Pokemon</p>
<%= form_for(#party) do |f| %>
<label>Party Name:</label>
<%= f.text_field :name %><br>
<label>Trainer Name:</label>
<%= collection_select(:party, :trainer_id, Trainer.order(:id), :id, :name, include_blank: true) %><br>
<label>Pokemon:</label>
<%= collection_select(:party, :pokemon1_id, Pokemon.order(:id), :id, :nickname, include_blank: false) %><br>
<%= f.submit %>
<% end %>
#schema
create_table "parties", force: :cascade do |t|
t.string "name"
t.integer "pokemon1_id"
t.integer "trainer_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
Lets start with the models. If you want a party to be able to include multiple pokemon you need to place the foreign key in the other model:
class Party < ApplicationRecord
belongs_to :trainer
has_many :pokemons # references the pokemons.party_id column
end
class Pokemon < ApplicationRecord
belongs_to :party # pokemons needs a `party_id` column
end
class AddPartyToPokemons < ActiveRecord::Migration
def change
add_reference :pokemons, :party, null: false, foreign_key: true
remove_column :parties, :pokemon1_id
end
end
This is very simplefied and assumes that Pokemon is an individual Pokemon and not the entire species and can only belong to a single party. Otherwise you need a many-to-many assocation with a join table/model.
In your controller you need to check if creating the record was actually successful and respond accordingly:
class PartiesController < ApplicationController
def new
#party = Party.new
end
def create
#party = Party.new(party_params)
if #party.save
redirect_to #party
else
render :new
end
end
private
def party_params
params.require(:party).permit(
:name,
:trainer_id,
pokemon_ids: []
)
end
end
If the user input is invalid this will render the app/parties/new.html.erb view and respond with it.
While you could use pry or byebug to step into the controller and check the errors you want to display the validation errors to the user in the view anyways so that they know what to actually do to correct the form:
<h1>Create a New Pokemon Party</h1>
<p>Select 6 Pokemon</p>
<%= form_for(#party) do |f| %>
<% if #party.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#party.errors.count, "error") %> prohibited this party from being saved:</h2>
<ul>
<% #article.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<%
# group labels and inputs in an element instead of abusing BR tags
# this lets you style the content with CSS
-%>
<div class="field">
<%# use f.label as it sets the `for=` attribute which is important for screen readers -%>
<%= f.label :name, 'Party Name:' %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :trainer_id, 'Trainer Name:' %>
<%# call the helper on the form builder to bind the input to the model -%>
<%= f.collection_select(:trainer_id, Trainer.order(:id), :id, :name, include_blank: true) %>
</div>
<div class="field">
<%= f.label :pokemon_ids, 'Pokemon:' %>
<%# call the helper on the form builder to bind the input to the model -%>
<%= f.collection_select(:pokemon_ids, Pokemon.order(:id), :id, :nickname, include_blank: false, multiple: true) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Note f.collection_select(:pokemon_ids, ...). This is a special setter/getter is generated by has_many :pokemons.

Option select with reference

I have 2 Models: Unit and Emp
Also I have 2 controllers: Units and Emps
class CreateEmps < ActiveRecord::Migration[6.0]
def change
create_table :emps do |t|
t.string :name
t.references :unit
t.timestamps
end
end
end
class CreateUnits < ActiveRecord::Migration[6.0]
def change
create_table :units do |t|
t.string :name
t.timestamps
end
end
end
Looks simple.... but I guess too simple. I haven't found example how to do the following:
I need to have form for Emp creation.
So my question is .... how should it look like?
I want to have ComboBox with list of all objects in Units.
<%= form_with model: #emp do |f| %>
<p><%= f.label :name %>
<%= f.text_field :name %> </p>
<!-- What should go here? to ComboBox (option->select) -->
<%= f.submit "Create" %>
<% end %>
I am also confused how should it look like regargding emp_params for permiting.
EDIT:
class EmpsController < ApplicationController
def new
#emp = Emp.new
#unit_options = Unit.all.collect{|unit| [unit.name, unit.id] }
end
def create
#emp = Emp.new(emp_params)
#emp.save
redirect_to :action => :list
end
def destroy
#emp = Emp.find([:id])
#emp.destroy
redirect_to :action => :list
end
def list
#emps = Emp.all
end
def emp_params
params.require(:emp).permit(:name, :unit_id)
end
end
You want to use a select tag.
In your controller:
#unit_options = Unit.all.collect{|unit| [unit.name, unit.id] }
This creates a list of names and IDs, the order of each is name then value for the select option. You can of course scope or filter the results as needed.
In your view:
<%= form_with model: #emp do |f| %>
<div>
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :unit_id, 'Unit' %>
<%= f.select :unit_id, #unit_options, {include_blank: true} %>
</div>
<%= f.submit "Create" %>
<% end %>
When used to edit the model, rails will select the option for the current value.

Unpermitted parameter: ROR

I am new in ror and when I submit my form:
<%= form_for :project, url: projects_path, html: {id:'form'} do |f| %>
<%= f.text_field :text, placeholder: 'Новая задача' %>
<%= link_to 'Отмена', '', id:'cancel_link' %>
<%= link_to 'Отправить', projects_path, id:'submit_link' %>
<% end %>
Have error:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"OR2HWCi3zVz9gB5VAmnzbEuzIwFGE58JlLrWQdNcws6FVTzqh5Cu0zvUJTUEv2O/sCvU9HuadJYr3mfA40ehGA==", "project"=>{"text"=>"NEW ITEM"}} Unpermitted parameter: :text
Have two models:
class Project < ApplicationRecord
has_many :todos
validates :title, presence: true
accepts_nested_attributes_for :todos
end
class Todo < ApplicationRecord
belongs_to :project, required: false
end
The Todo model has a text attribute in which our todo should be located
Controller
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def create
#project = Project.new(project_params)
if #project.save
redirect_to root_path
end
end
def update
end
private
def project_params
params.require(:project).permit(:title, todos_attributes: [:id, :text])
end
end
Project db
class CreateProjects < ActiveRecord::Migration[5.2]
def change
create_table :projects do |t|
t.string :title
t.string :todos
t.timestamps
end
Todo db
class CreateTodos < ActiveRecord::Migration[5.2]
def change
create_table :todos do |t|
t.text :text
t.boolean :isCompleted
t.integer :project_id
t.timestamps
end
I'm requesting the todo attributes using accepts_nested_attributes_for: todos, the controller is also registered on the guides, in project_params I request todos_attributes. But when sending a form to the database, the value is text. He does not save in db. Can u help please
In order to save text field in Todo model, you have to create nested form. Use nested_form gem for this purpose.
A vague example to show how it works:
<%= nested_form_for :project, url: projects_path, html: { id: 'form' } do |f| %>
<%= f.text_field :title, placeholder: 'Новая задача' %>
<%= f.fields_for :todos do |todo_form| %>
<%= todo_form.text_field :text %>
<%= todo_form.link_to_remove "Remove this todo" %>
<% end %>
<p><%= f.link_to_add "Add a todo", :todos %></p>
<%= link_to 'Отмена', '', id:'cancel_link' %>
<%= link_to 'Отправить', projects_path, id:'submit_link' %>
<% end %>
In controller, to have the functionality of removing a todo in case of editing a project:
def project_params
params.require(:project).permit(:title, todos_attributes: [:id, :text, _destroy])
end
In the migration CreateProjects < ActiveRecord::Migration[5.2], I do not think that you require todos as a string.
The form which you created is wrong, you need to create a nestead_form
It is giving you and Unpermitted parameter error because the text is not a field of project model you can check this on your migration file. You need to change it to title because the title is the field of project model.
And for to create a nested form you need to do some changes in your form
<%= form_for :project, url: projects_path, html: {id:'form'} do |f| %>
<%= f.text_field :title, placeholder: 'Новая задача' %>
<%= f.fields_for :todos do |todo| %>
<%= f.text_field :text %>
<% end %>
<%= link_to 'Отмена', '', id:'cancel_link' %>
<%= link_to 'Отправить', projects_path, id:'submit_link' %>
<% end %>

Not able to save data into Model

I can't save the data into my model. Every time when the code run it will ran into the else statement which failed to save the data in the CREATE action. Any idea?
This is my invoices_controller.rb
class InvoicesController < ApplicationController
def new
#permits = Permit.find(params[:permit_id])
#invoice = Invoice.new
end
def create
#permit = Permit.find(params[:permit_id])
#invoice = #permit.build_invoice(invoice_params)
if #invoice.save
redirect_to payment_path
else
redirect_to root_path
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invoice
#invoice = Invoice.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invoice_params
params.require(:invoice).permit(:vehicle_type, :name, :department, :carplate, :duration, :permitstart, :permitend, :price, :time)
end
end
Invoices/new.html.erb ( This is the data I wanted to save)
<% provide(:title, 'Invoice') %>
<h1>Invoice</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3" id="datashow">
<%= form_for(#invoice) do |f| %>
<h2>Time : <%=#permits.created_at%></h2></br>
<h2>Invoice ID : <%=#permits.id%></h2></br>
<%= f.label :"Vehicle" %>
<%= f.text_field :vehicle_type, :value => #permits.vehicle_type, readonly: true %>
<%= f.label :"License Plate" %>
<%= f.text_field :carplate, :value => #permits.carplate, readonly: true %>
<%= f.label :"Student ID" %>
<%= f.text_field :studentid, :value => #permits.studentid, readonly: true %>
<%= f.label :name %>
<%= f.text_field :name, :value => #permits.name, readonly: true %>
<%= f.label :"Department of applicant" %>
<%= f.text_field :department, :value => #permits.department, readonly: true %>
<%= f.label :permit_start %>
<%= f.text_field :permitstart, :value => #permits.permitstart, readonly: true %>
<%= f.label :permit_end %>
<%= f.text_field :permitend, :value => #permits.permitend, readonly: true %>
<%= f.label :"Price" %>
<%= (f.text_field :price, :value => '$AUD 50' , readonly: true) %>
<%= hidden_field_tag(:permit_id, #permits.id) %>
<%= f.submit "Make Payment", class: "btn btn-primary" %>
<% end %>
</div>
</div>
Invoice.rb
class Invoice < ApplicationRecord
belongs_to :user
has_one :receipt
belongs_to :permit
end
Permit.rb
class Permit < ApplicationRecord
belongs_to :user
has_one :invoice
end
If you are unsure why your object is not created, you have multiple options.
First you can use #invoice.save! instead of #invoice.save during debugging. This will raise an exception and give you some clues, what's going wrong.
Or you can use a debugger and inspect #invoice.errors.full_messages.
Further more you can output #invoice.errors.full_messages via Rails.logger.error #invoice.errors.full_messages.to_sentence.
Or you can use the error message as a flash message flash[:error] = #item.errors.full_messages.to_sentence
This should help you find the error.
from: build method on ruby on rails
build won't "create" a record in database, just create a new object in memory so that the view can take this object and display something, especially for a form.
So build isn't working because you aren't creating (create and saving) a record. build doesn't save a record.
Try:
def create
#permit = Permit.find(params[:permit_id])
#invoice = #permit.invoices.create(invoice_params)
if #invoice.save
redirect_to payment_path
else
redirect_to root_path
end
end

Rails passing params to different model and then saving it not working

I have a 'post' controller in that I have two variable title and body which I am passing through strong parameters.But I need to use two other variable which are path and name which are in different model name 'Document'..And also I am saving the content in database ..but unable to do so..getting this error view [posts/_form.html.erb]
undefined method `name' for #
[posts_controller]
class PostsController < ApplicationController
before_action :authenticate_user!
def index
#posts = Post.user_post(current_user).order('created_at DESC').paginate(:page => params[:page], :per_page => 5)
end
def new
#post = Post.new
end
def show
#post = find_params
end
def create
#post = Post.create(post_params)
#post.user = current_user
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
#post = find_params
end
def update
#post = find_params
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = find_params
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body)
Document.new(params,:files=>[])
end
def find_params
Post.find(params[:id])
end
end
[post/_form.html.erb]
<%= form_for #post,html: { multipart: true } 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 %>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
<br>
<%= f.label :body %><br>
<%= f.text_field :body %><br>
<br>
<%= f.label :name %> <br>
<%= f.text_field :name %><br>
<br>
<br>
<%= f.label :path %><br>
<%= f.file_field :path %><br>
<%= f.submit %>
<% end %>
[document.rb]
class Document < ActiveRecord::Base
validates :name, presence: true
validates :path, presence: true
validates :resource_type, presence: true
validates :resource_id, presence: true
mount_uploader :path, PathUploader
validates :name, presence: true
# def self.abc
# params.permit(:name,:path)
# end
def initialize(params,file)
params=file[:name]
#params.permit(name =>:name,path =>:path)
end
end
undefined method `name' for #
You're referencing a non-existent attributes for your Post form:
<%= form_for #post,html: { multipart: true } do |f| %>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
<br>
<%= f.label :body %><br>
<%= f.text_field :body %><br>
<%= f.submit %>
<% end %>
Remove :name & :path references.
--
If you want to pass "extra" attributes to another model, you need to use accepts_nested_attributes_for or set the params separately to your "primary" model:
#app/models/post.rb
class Post < ActiveRecord::Base
has_many :documents
accepts_nested_attributes_for :documents
end
#app/models/document.rb
class Document < ActiveRecord::Base
belongs_to :post
end
This will allow you to pass the documents as "nested" attributes of your Post model:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def new
#post = Post.new
#post.documents.build
end
def create
#post = Post.new post_params
#post.save
end
private
def post_params
params.require(:post).permit(:title, :body, documents_attributes: [:name, :path])
end
end
#app/views/posts/_form.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.fields_for :documents do |d| %>
<%= d.text_field :name %>
<%= d.text_field :path %>
<% end %>
<%= f.submit %>
<% end %>
So undefined method on a model will indicate that, well, the method doesn't exist on the model. Want to see a model's methods? Post.methods. However, in this example, the column name is not defined on the model., and you're trying to tell Post that it has a name. What you need to do is nest your parameters.
While there is a ton of cleaning up that might want to focus on first, your answer is found in the accepts_nestable_attributes_for class methods, as shown here, http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html, and strong_params documentation as shown here, http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
In your case, you want to create a new document from a post. Your permitted params hash will look like this,
params.require(:post).permit(:title, :body, :document_attributes => [:name])
Ensure that document_attributes is singular; if a person has_many pets (for example), then you'd have pets_attributes.
In your form, something that often trips people up is the builder.
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.fields_for #post.document do |document_field| %>
<%= document_field.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
Make sure that you're telling ERB that <%= f.fields_for %>, not just <% f.fields_for %>.

Resources