form_for renders get rather than post, using rails - ruby-on-rails

I have a long form that auto-fills with information from our database (based upon partial information supplied by a user). When the user verifies the information and re-submits the form, the information should be saved as the users. The form - qualifying_events - is a partial that's in the views / shared folder. The data that autofills it is rendered by the qualifying_events_controller as part of the create method. The partial is presented for verification in a views / users page that's rendered by the user controller. The initial, partial information input by a user - in a similar partial on the same page - is correctly saving. Here's the top of the form:
<form class="form-inline">
<%= form_for(#qualifying_event) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div >
<div class="form-group col-sm-12 text-center" style="margin-bottom: 5px;"><h5>
<div>
<li style="list-style-type: none; float: left; display: none; visibility: hidden;">
<%= current_user %>
</li>
</div>
<div>
<li style="list-style-type: none; float: left;">
<%= f.label :class_date %><br/>
<%= f.text_area :class_date, autofocus: true %>
</li>
</div>
Here is the error message:
No route matches [GET] "/qualifying_events"
Here's what I've tried:
1. Explicitly adding a route to the config / routes file although it already showed if I ran rake routes:
post 'qualifying_events_path' => 'qualifying_events#create'
2. Changing the form_for language to explicitly call 'post':
<%= form_for(#qualifying_event, url: qualifying_events_path, method: => post) do |f| %>
I still get the same error message. Since I have other forms that are saving to the database with the same code, I have to assume something changes when a form is populated from a database and one wants to re-save the information. I'm using the devise gem so I looked at the registration#edit code, hoping I could follow the format:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
Unfortunately, that approach didn't work either.
For 'completeness', here's the qualifying_events_controller code:
def create
#user = current_user
#qualifying_event = current_user.qualifying_events.build(qualifying_event_params)
if #qualifying_event.validated.nil?
# Match partial course information from current_user with records in table
# Get partial record's information
active_date = #qualifying_event.class_date
active_course = #qualifying_event.course_id
active_sponsor = #qualifying_event.sponsor_name
# Match on class_date, course_id, and sponsor_name
#qualifying_event = QualifyingEvent.new
#qualifying_event.assign_attributes(QualifyingEvent.
where("(class_date = :class_date AND course_id = :course_id)
OR (class_date = :class_date AND sponsor_name = :sponsor_name)
OR (course_id = :course_id AND sponsor_name = :sponsor_name)",
{class_date: active_date, course_id: active_course,
sponsor_name: active_sponsor}).first.attributes)
# render to confirmation form / form for completion
flash[:success] = "Qualifying Event saved for verification!"
respond_to do |format|
format.html {render 'users/user_dashboard' }
end
else
# if the record is complete
#qualifying_event.save
flash[:success] = "Qualifying Event created!"
redirect_to user_dashboard_path
end
There may be an error in the 'else' statement. I haven't yet added the code to verify that all the required information is present, etc.
I can save to and retrieve information from the database, however a re-submit of edited information calls 'get' rather than 'post.' What am I missing? Thank you in advance.

Remove the first <form> element and fix your form_for code from:
<%= form_for(#qualifying_event, url: qualifying_events_path, method: => post) do |f| %>
to:
<%= form_for(#qualifying_event, url: qualifying_events_path, method: :post, class: 'form-inline') do |f| %>

Remove <form class="form-inline"> (and the closing tag if any) before form_for. HTML forms can't be nested, thus only the outer form are processed which is have GET method.

Related

Rails send email via pop up

I have created a form, which has a field which onclick() leads to opening up of a pop up (Invite Importer).
In this pop up, the customer has to input certain information and when it is inputted, I want all the information to be saved and email to be triggered with the inputted email. All this should happen when I click on submit (shown in below image as "Speichern").
How would I do it?
I have thought about creating 2 forms. One popup and the other base, but the submit button would lead to both of them being submitted.
how do you i save and submit email with pop up without the other form being submitted.
Make sure the html for the second form is not inside the main form. That will cause issues. You also probably want the modal form to be remote: true so that it will be submitted via AJAX. Instead of:
<%= form_for #model do |form| %>
...
<%= form.text_field :foo, onclick: 'openEmailModal()' %>
<div class="modal etc" id="email-modal">
<%= form_for #email do |form2| %>
...
<% end %>
</div>
<% end %>
You will have:
<%= form_for #model do |form| %>
...
<%= form.text_field :foo, onclick: 'openEmailModal()' %>
<% end %>
<div class="modal hide etc" id="email-modal">
<%= form_for #email, remote: true do |form| %>
...
<% end %>
</div>
In your views you can create a file named create.js.erb for example that would do something like:
closeEmailModal(); // this is just straight javascript
$('#notices').html("<%= escape_javascript(render 'my_partial') %>"); // reuse html your partials in JS
$('#notices').html("<%= j(render 'my_partial') %>"); // or use j (it's an alias for escape_javascript)
alert('I did stuff!');

in rails difference between form_for #article and form_for :article

im new to ruby on rails, abit confused between the usage of the following when i try to update a record:
<%= form_for #article, url:{action: "update"} do |form| %>
this one works, but i dont understand how come the submit button says 'update article'
<%= form_for :article, url:{action: "update"} do |form| %>
this one throws No route matches [POST] "/articles/2", and the submit button says 'save article'
finally:
<%= form_with(model: #article) do |form| %>
actually updates the record, but i dont understand why it's calling update, and not other methods
form_for(#article) creates a form builder which is bound to a model instance.
If #article is nil it will raise an error.
If the instance is a new record the form will use method="POST" and action="/arcticles".
If the record has been persisted it will have method="PATCH" and action="/arcticles/:article_id".
Rails derives the URL for the action attribute based on convention over configuration. So there is no need to explicitly pass the url option if you follow the conventions.
An example of this would be:
<% #article = Article.new(title: 'Hello World') %>
<%= form_for(#article) do |f| %>
<%= f.text_input :title %>
<% end %>
This will render something like:
<form action="/articles" method="POST">
<input type="text" name="article[title]" value="Hello World"/>
...
</form>
<%= form_for #article, url:{action: "update"} do |form| %> this one
works, but i dont understand how come the submit button says 'update
article'
The form builder knows it is updating an record by calling .new_record? on the the record you passed to form_with. You can change the default value of the submit button by providing translations:
# config/locales/en.yml
en:
helpers:
submit:
create: "Save new record"
update: "Save changes"
form_for(:article) creates a scoped form builder that does not wrap an object.
This creates a form builder where the inputs will be "scoped". For example:
<%= form_for(:article) do |f| %>
<%= f.text_input :title %>
<% end %>
This will render something like:
<form action="/articles" method="POST">
<input type="text" name="article[title]"/>
...
</form>
Rails derives the URL for the action attribute based on convention over configuration.
In your case <%= form_for :article, url:{action: "update"} do |form| %> causes a routing error since form_for defaults to method: "POST".
form_with is the Rails 5.1 replacement for form_for and form_tag
form_with will replace the form_for and form_tag methods which are closely related yet have very different signatures. form_for and form_tag have been soft depreciated and are slated for removal.
The idea is to provide a single method with a more consistent signature.
If you are using Rails 5.1+ this is what you should be using.
See:
Rails Guides - Action View Form Helpers
Rails API - ActionView::Helpers::FormHelper
Rails 5.1's form_with vs. form_tag vs. form_for
It all depends on #artical. If #artical is new object (id in #artical is nil) is call the create action. If #artical is existing object then it called the update method.

Ruby on Rails: Search collection_check_boxes on a form

In my RoR application I have functionality that allows a user to select contacts to send an email to. I want to add to this functionality so that a user can search the contacts.
Currently, the contacts are displayed on the views/emails/form.html.erb in checkboxes that the user can select through:
<%= f.collection_check_boxes :contact_ids, Contact.where(user_id: session[:user_id]), :id, :firstname %>
Is it possible to build on this by adding a search bar above the checkboxes that allows the user to search the checkboxes by first name?
You can have a form to work with an unobstrusive javascript.
Like
<div class="form-group">
<!-- Form outside your main form... the REMOTE flag will tell rails
to prevent the default behaviour of a form make a request
for JS response --!>
<%= form_tag contacts_path, remote: true, method: :get do %>
<%= input_tag :search %>
<%= button_tag "Search" %>
<% end %>
<div id="email-form">
<%= form_for #email, email_path do |f| %>
<!-- Many inputs relative with email omited--!>
<div class="contact-list">
</div>
<%= f.submit 'Submit' %>
<% end %>
</div>
Have an controller/action that search for your contacts and returns it for a js view...
// ContactController
def index
respond_to do |format|
format.html { #contacts = Contact.all }
format.js { #contacts = Contact.find_by(firstname: params[:search]) }
end
end
And have a view for that action/controller that manipulate the html to append the contacts to be selected
// views/contacts/index.js.erb
$(document).ready(function() {
$('#contact-list').append("<%= collection_check_boxes :email, :contact_ids, #collection, :id, :firstname %>")
})
That is a very simple example... and I don't handle repetition... if you search for the same thing twice...

"No route matches [POST]" despite Resources in my Routes file

I am creating a Rails app, and I need a form to function in one of my views and submit data to a table without the use of a scaffold (like I usually do).
Now, the place where this comment form is going to appear is in one view within the blog folder. It will need to allow the user to put in their comment, save it to the table, and then return to the same page.
While this is a pretty commonplace error, I am confused because I am specifying two things that seem critical: creating resources in my routes file for the form, and second, using a create method in my controller.
In the blog.html.erb, this happens in this form:
<%= form_for :cements do |f| %>
<div class="form-group">
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :post, class: "form-control" %>
</div>
</div>
<h5 id="username">Username</h5>
<div class="form-group">
<div class="field">
<%= f.text_field :username, class: "form-control" %>
</div>
</div>
<%= f.hidden_field :slug, :id => "hiddenPicker"%>
<div class="actions">
<%= f.submit "Save", class: "btn btn-success-outline" %>
</div>
<% end %>
Then, in my controller, I have a create method that should redirect back to the original page, as I wanted.
blogs_controller.rb
class BlogsController < ActionController::Base
def index
#posts = Post.order('updated_at DESC').all
#comments = Cement.all
end
def blog
#posts = Post.where(slug: params[:id]).all
#comments = Cement.all
end
def create
#cements= Cement.new(story_params)
#cements.save
redirect_to(:back)
end
private
def story_params
params.require(:cements).permit(:username, :post, :slug)
end
end
Good news: the comment form renders in the view. Bad news: when I submit, I am getting this error: No route matches [POST] "/blog".
My expectation is this will be an issue with my Routes file; however, I have a resources method already in there:
Rails.application.routes.draw do
resources :posts
resources :cements
resources :blogs
The naming convention is the same as my controller file, so I am confused why this error is happening. Any ideas?
:cement is not an object it is just a symbol, so how rails will determine where to POST form? If you inspect your form you will see form action as /blog (current page url).
You should either do
<%= form_for :cements, url: cements_path do |f| %>
or
<%= form_for Cement.new do |f| %>
Both of above will generate form action as /cements, which will submit to CementsController create action, But I see in your case you want to submit it to BlogsController so use the appropriate routes(blogs_path). You can use url in second version also.

How do I pass a parameter to a form partial that is shown via CSS?

So my form partial is loaded in my div id="secondary", which is hidden on first page load.
When the user hits a button with a class called toggleSidebar, then the _form.html.erb is shown.
I have overridden the partial to display a new form (even if update is pressed) when a user is not logged in like this:
<%= simple_form_for(Post.new, html: {class: 'form-horizontal' }) do |f| %>
As opposed to the regular version that looks like this, and is included in an if statement on this same partial:
<% if current_user and current_user.has_any_role? :editor, :admin %>
<%= simple_form_for(#post, html: {class: 'form-horizontal' }) do |f| %>
The real issue is in my view, when someone goes to Update, this is what happens when the user is logged out:
<%= link_to "Update", "#", class: "togglesidebar" %>
This is perfect, it executes the CSS and shows the empty form partial perfectly.
However, when a user is logged in, I want it to send the parameter parent_id: #post with the execution of the sidebar being toggled.
This is how it looks with a normal new_post_path view (i.e. the non-sidebar new post view):
<% if current_user %>
<%= link_to "Update", new_post_path(parent_id: #post) %>
<% end %>
This is what my PostController#New looks like:
def new
#post = Post.new(parent_id: params[:parent_id])
end
How do I either pass the params in the regular non new_post_path version, or tackle this another way?
You could probably use a helper method.
Just browse to the 'helper' directory under 'app' folder and create a file similar to [name]_helper.rb
In this file create a module by [name]Helper and declare your helper method in this module.
This module is automatically required by rails.
A small example might help you.
The code in the link_helper.rb under app/helper directory
module LinkHelper
def populate_link(link1, link2, parameter)
if current_user
public_send(link2, parameter)
else
link1
end
end
end
The code in views is
<%= link_to 'update', populate_link('#', 'new_requirement_path',parameter: 33) %>
I'm a bit confused by the question, but I think you may be just need to use a hidden field to pass the parent_id param back?
e.g./
<%= simple_form_for(Post.new, html: {class: 'form-horizontal' }) do |f| %>
<%= f.hidden_field :parent_id, { value: #post.try(:id) } %>
<% end %>
HTH?
I am also a bit confused, but the following railscast might help you. It shows how to embed data in an html-tag. You can probably do it the same way.
railscast-> passing data to javascript
Out of the possibilities there I'd recommend the data-attribute:
<%= simple_form_for,(Post.new, html: {class: 'form-horizontal' }, **data: {post_id: #post.id}**) do |f| %>
<% end %>

Resources