Routing problems with STI - ruby-on-rails

I've declared an STI on Works
class Work < ActiveRecord::Base
validates :title, presence: true
validates :visibility, presence: true
belongs_to :category
end
class Story<Work
end
class Poem<Work
end
Code for form:
<div class="panel panel-blue margin-bottom-40">
<div class="panel-heading">
<h3 class="panel-title"><i class="icon-tasks"></i> Item Details</h3>
</div>
<div class="panel-body">
<%= form_for(#work, :html =>{:class =>"margin-bottom-40 new_item ",:multipart => true}) do |f| %>
<% if #work.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#work.errors.count, "error") %> found </h2>
<ul>
<% #work.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label "Title",:class=>"control-label" %>
<div class="controls">
<%= f.text_field :title,:class=>"form-control",:placeholder=>"Title of the story/poem" %>
<div class="description">
<div class="">
<strong>Enter a suitable title for your story/poem
</strong>
</div>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :type,:class=>"control-label" %>
<div class="controls">
<%= f.select :type,{"Story"=>"Story","Poem"=>"Poem"},{},:class=>"form-control",:placeholder=>"Story/Poem" %>
<div class="description">
<div class="">
<strong>Is it a story or a poem?
</strong>
</div>
</div>
</div>
</div>
<%
visibilities=["Me Only","Anyone with link","Logged In Users","Everyone"]
%>
<div class="form-group">
<%= f.label :visibility,:class=>"control-label" %>
<div class="controls">
<% [ 3,2, 1, 0 ].each do |option| %>
<br><%= radio_button_tag :visiblity, option, #visibility == option %>
<%= label_tag "visibility_#{option}", visibilities[option].humanize %>
<% end %>
<div class="description">
<div class="">
<strong>
</strong>
</div>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :category_id,:class=>"control-label" %>
<div class="controls">
<%= f.collection_select :category_id,Category.all,:id,:name,{},:class=>"form-control" %>
<div class="description">
<div class="">
<strong>
Type your story/Poem here
</strong>
</div>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :content,:class=>"control-label" %>
<div class="controls">
<%= f.text_area :content,:class=>"form-control" %>
<div class="description">
<div class="">
<strong>
</strong>
</div>
</div>
</div>
</div>
<div class="actions">
<%= f.submit :class=>"btn btn-primary" %>
<%= link_to 'Back', works_path,:class=>"btn" %>
</div>
<% end %>
I have scaffolding for work with the parameter Type which accepts Story and Poem. When I submitted the form initially, I would get a stories_path not found error so I mapped stories and poems paths as follows:
resources :stories, :controller => 'works'
resources :poems, :controller => 'works'
So when I submit the first time, the form shows validation errors. When I submit it again after correcting validation, I get an exception
ActionController::ParameterMissing in WorksController#create
in this line:
params.require(:work).permit(:title, :type, :visibility, :category_id, :content)
I assume this is because its now renaming all the fields to story[] instead of work[]
How do I fix this and in the greater picture, how do I make STI work on the same controller. I just want to be able to use Poem.all and Story.all for fetching records.
Submisson currently works through the same interface
I am allowing the user to select the type of work in the form.

Related

Nil:nil class error on each loop when Form to build object loaded on page first

I have a form on a page that is building a “tip” for a “guide”. Below the form, I am running an each loop over all the #guide.tips. I keep getting an error as the each loop is loading the forms blank object as it sees it as a tip. I’ve currently solved the problem by using jQuery to inject the form after page load, but there has to be a better solution.
Each Loop on Guide.html.erb
<% if !#guide.tips.blank? %>
<% #guide.tips.each do |tip| %>
<div class="row mx-1">
<div class="col-md-3 border-right">
<div class="float-left">
<%= image_tag avatar_url(tip.user), class: "float-left text-left align-middle rounded img-fluid mx-3", width: "30%" %>
<p><%= tip.user.fullname %></p>
</div>
<div class="float-right mr-3">
<%= link_to like_tip_path(tip), method: :put do %>
<div class="fas fa-angle-up"></div>
<%= tip.get_upvotes.size %>
<% end %><br/>
<%= link_to dislike_tip_path(tip), method: :put do %>
<div class="fas fa-angle-down"></div>
<%= tip.get_downvotes.size %>
<% end %>
</div>
</div>
<div class="col-md-8 ml-3">
<h6><%= tip.title %> -<span class="ml-1"><small><%= tip.created_at.strftime("%A, %d %b %Y %l:%M %p")%></small></span></h6>
<%= tip.tip %>
</div>
</div><hr/>
<% end %>
<% end %>
Tips_Controller.rb
def new
#guide = Guide.find(params[:guide_id])
#tip = Tip.new
end
def edit
end
def create
#guide = Guide.find(params[:guide_id])
params[:tip][:user_id] = current_user.id
#tip = #guide.tips.create!(tip_params)
redirect_to guide_path(#guide)
end
Tip Form Partial
<%= form_for([#guide, #guide.tips.build]) do |f| %>
<div class="form-group row">
<div class="col-sm-12">
<p class="text-left">Tip Title</p>
<%= f.text_field :title, placeholder: "Enter Title", class: "form-control" %>
</div>
<div class="col-sm-12 mt-2">
<p class="text-left">Your Tip</p>
<%= f.text_area :tip, placeholder:"What's your tip for this travel guide?", class: 'form-control' %>
</div>
</div>
<div class="form-group row">
<div class="col-md">
<%= f.submit 'Submit', class: 'btn btn-primary btn-block' %>
</div>
</div>
<% end %>
Here is another solution that does not separate the logic between the controller and the view and cleans up your empty array statement for your loop
Each Loop on Guide.html.erb
<% #guide.tips.each do |tip| %>
<div class="row mx-1">
<div class="col-md-3 border-right">
<div class="float-left">
<%= image_tag avatar_url(tip.user), class: "float-left text-left align-middle rounded img-fluid mx-3", width: "30%" %>
<p><%= tip.user.fullname %></p>
</div>
<div class="float-right mr-3">
<%= link_to like_tip_path(tip), method: :put do %>
<div class="fas fa-angle-up"></div>
<%= tip.get_upvotes.size %>
<% end %><br/>
<%= link_to dislike_tip_path(tip), method: :put do %>
<div class="fas fa-angle-down"></div>
<%= tip.get_downvotes.size %>
<% end %>
</div>
</div>
<div class="col-md-8 ml-3">
<h6><%= tip.title %> -<span class="ml-1"><small><%= tip.created_at.strftime("%A, %d %b %Y %l:%M %p")%></small></span></h6>
<%= tip.tip %>
</div>
</div><hr/>
<% end unless #guide.tips.blank? %>
Tip Form Partial
By creating the Tip from outside the association (i.e. not using build), it will not be loaded into the class variable's children
<%= form_for([#guide, Tip.new(guide: #guide)]) do |f| %>
<div class="form-group row">
<div class="col-sm-12">
<p class="text-left">Tip Title</p>
<%= f.text_field :title, placeholder: "Enter Title", class: "form-control" %>
</div>
<div class="col-sm-12 mt-2">
<p class="text-left">Your Tip</p>
<%= f.text_area :tip, placeholder:"What's your tip for this travel guide?", class: 'form-control' %>
</div>
</div>
<div class="form-group row">
<div class="col-md">
<%= f.submit 'Submit', class: 'btn btn-primary btn-block' %>
</div>
</div>
<% end %>
Another Example / Q&A
Using the structure you already have you could do:
<% if #guide.tips.count > 1 %> (assuming this will always be shown with an empty "build" tip)
or you can use:
<% next unless tip.persisted? %>
inside the loop, before the actual form.
You also don't need the blank? check as an .each on an empty enumerator simply won't execute the block, and as long as there's a has_many relationship between guide and tips it will always yield a collection proxy.
I would write it as:
<% #guide.tips.each do |tip| %>
<% next unless tip.persisted? %>
<div class="row mx-1">
<div class="col-md-3 border-right">
...
<% end %>

How to add in multiple options for checkbox in Ruby on Rails?

This is likely a super easy answer for a Ruby on Rails expert. I have a form and need to add in a checkbox that has multiple items. I've been messing with the following code for a lot longer than I'd like to admit:
<%= form_for :lead, url: something, html: {id: 'product-form'} do |f|%>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<%= f.label :product%>
<%= f.check_box :product, {multiple:true}, "option", "option2", :class => 'form-control'%>
</div>
</div>
</div>
<% end %>
With this code I get the error "wrong number of arguments (5 for 1..4)".
Basically I just want someone to be able to pick multiple options. I've also tried the following:
<div class="row">
<div class="col-md-12">
<div class="form-group">
<%= f.label :product%>
<%= f.check_box :option1, "Option1" :class => 'form-control'%>
<%= f.check_box :option2, "Option2", :class => 'form-control'%>
</div>
</div>
</div>
And I get the delightful "undefined method `merge' for "Option1":String". What am I missing to put the values in associated with the label?
I use Rails 5.1.6 and this is how I achieved adding multiple options for checkbox. I also placed it in a dropdown.
In the migration file:
t.string :skills
In my controller "tasks_controller.rb":
def task_params
params.require(:task).permit(:work_type, :title, :post, {skills: []})
end
In my model "task.rb" I did:
validates :skills, presence: true
serialize :skills, JSON
I created a module mobilephones_data.rb in directory "app/model/concerns/" which holds all the options of the checkbox as an array that can be edited easily.
In app/model/concerns/mobilephones_data.rb I wrote:
module Mobilenphones_Data
Activities = [
'Amazon Kindle', 'Blackberry', 'iPad', 'iPhone', 'Mobile Phone', 'Nokia',
'Palm', 'Samsung'
]
end
This will put all data from module's array into the checkbox drop-down as checkbox options. In My form I did:
<div class="card">
<a class="card-link card-header" data-toggle="collapse" href="#collapseOne">
Mobile Phones
</a>
<div id="collapseOne" class="collapse" data-parent="#accordion">
<div class="card-body">
<% Mobilenphones_Data::Activities.each do |activity| %>
<div id="skill_list" class="col-lg-3 col-md-4 col-sm-12 col-12">
<%= f.check_box :skills, { multiple: true }, activity, false %>
<%= activity %>
</div>
<% end %>
</div>
</div>
</div> <!--bottom-->
</div>
In my view "show.html.erb":
<% #name_of_model.skills.each do |skill| %>
<%= skill %>
<% end %>
For posterity sake:
<div class="row">
<div class="col-md-12">
<div class="form-group">
<%= f.label "Select a Product" %><br />
<%= f.check_box(:option) %>
<%= f.label(:mug, "Option") %><br />
<%= f.check_box(:option2) %>
<%= f.label(:mousepad, "Option2") %>
</div>
</div>
</div>

Submitting two forms in Rails sharing a same param

I have a form like that:
<%= form_for #report do |f| %>
<div class="row">
<div class="col-sm-9">
<h3 class="page-header">
Children
</h3>
<div class="row">
<% students.each do |student| %>
<div class="col-xs-4 col-md-2">
<div class="std_container">
<%= check_box_tag "student_ids[]", student.id, nil, {id: "check_#{student.id}", class: "student_check"} %>
<%= label_tag "check_#{student.id}" do %>
<div class="std_label"><%= student.name %></div>
<div class="std_img thumbnail"><img src="http://www.codeproject.com/KB/GDI-plus/ImageProcessing2/img.jpg" alt=""></div>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<%= render "form_categories", f: f, report_notes: #report.report_notes %>
<%= render "messages/form", ????? %>
</div>
</div>
</div>
<% end %>
And I need to render these two partials on the bottom. The 'messages' partial is a form that responds to a different controller but needs to use the "student_ids[]" parameter present on the #report form together with its own parameters. This partial is:
<%= form_for #message do |f| %>
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
<%= f.hidden_field :professor_id, :value => current_user.professor.id %>
<%= f.label :text, "Texto" %>
<%= f.text_area :text %>
<%= f.submit "Enviar", class: "btn btn-default" %>
</div>
</div>
<% end %>
How do build this "messages" partial in a way that I can use the "student_ids[]" and submit it to its controller?
It is not possible. I solved this problem by using javascript.

Missing partial invoices/__invoice_item_fields

i have invoice and invoice_items models in my application. and i have used cocoon gem for nested models.i am using rails 4.2. it is working properly when i am creating new invoice, but when i am clicking on my edit button i am getting "template missing error" though i have _invoice_item_fields.html.erb file in my application.
this is my _form.html.erb file
<div class=" form">
<%= form_for(#invoice,:html=>{:class=>"cmxform form-horizontal tasi-form",:novalidate=>"novalidat"}) do |f| %>
<% if #invoice.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#invoice.errors.count, "error") %> prohibited this invoice from being saved:</h2>
<ul>
<% #invoice.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group ">
<%= f.label :billing_address ,:class=>"control-label col-lg-2" %>
<div class="col-lg-6">
<%= f.text_area :billing_address,:class=>"form-control" %>
</div>
</div>
<div class="form-group ">
<%= f.label :shipping_address ,:class=>"control-label col-lg-2" %>
<div class="col-lg-6">
<%= f.text_area :shipping_address,:class=>"form-control" %>
</div>
</div>
<div class="form-group ">
<%= f.label :company_id ,:class=>"control-label col-lg-2" %>
<div class="col-lg-6">
<%= f.number_field :company_id,:class=>"form-control" %>
</div>
</div>
<div class="form-group ">
<%= f.label :invoice_date ,:class=>"control-label col-lg-2" %>
<div class="col-lg-6">
<%= f.date_select :invoice_date,:class=>"form-control" %>
</div>
</div>
<div class="form-group ">
<%= f.label :status ,:class=>"control-label col-lg-2" %>
<div class="col-lg-6">
<%= f.number_field :status,:class=>"form-control" %>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<section class="panel">
<header class="panel-heading">
Invoice Items
<span class="pull-right">
<%= link_to_add_association 'Add Item', f, :invoice_items,:class=>"btn btn-default"%>
</span>
</header>
<div class="panel-body">
<div class="adv-table">
<%= f.fields_for :invoice_items do |item| %>
<%= render '_invoice_item_fields', :f => item %>
<% end %>
</div>
</div>
</section>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<%= f.submit "Save",:class=>"btn btn-danger"%>
</div>
</div>
<% end %>
</div>
this is my _invoice_item_fields.html.erb file
This...
<%= render '_invoice_item_fields', :f => item %>
must be
<%= render 'invoice_item_fields', :f => item %>
You do not use a leading _ in your Rails render call to render a partial. The underscore goes on the filename on disk only.

Submitting a form doesn't work after time, only after refreshing

I have a Simple Form and i just realized that if edit the form long enough (5-10secs) the Submit button suddenly doesn't work.
If i refresh the page and quickly type some letters and the submit it, it works...
This behavior is active on everything in my app that has a scaffold form, for example my Devise form's are just fine.
I have no idea what is causing this behavior.. What am i missing ?
EDIT
This behavior occurs only in Google Chrome Browsers.
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<h1>Test Form</h1>
</div>
</div>
<div class="panel-body">
<%= form_for(#question) do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :title %><br>
<%= f.text_field :title, class: "form-control", :autofocus => true,
placeholder: "#"%>
</div>
<div class="form-group">
<%= f.label :body %><br>
<%= f.text_area :body, class: "redactor redactor-box" %>
</div>
</div>
<div class="panel-footer">
<div class="form-group">
<%= f.submit "Post", class: "btn btn-primary" %>
</div>
</div>
<% end %>
</div>
It seems that the problem was in the HTML.
I wrapped all my html tags with form_for and for now it seems to be working..

Resources