Rails, 1 form, two buttons. Search and New - ruby-on-rails

I think I'm trying to do something similar to this question but in rails. I would like to have a search form of sorts, but instead of two separate forms I want to use one text input and have two submit buttons, one which initiates a search and the other begins creating a new work order using the parameter from the form. I have already implemented the second half, but can't seem to find an obvious way to do it. This rails cast seems to start to get at what I want, but it seems like the rails helpers are getting in the way more than anything. Is there any way to do this without javascript? Also it seems like I'm mixing raw html with rails erb, so I suspect that can be improved as well. Unless it turns out rails simply can't do what I want then does that mean I need to resort to straight up HTML or even javascript? My only hesitation to use javascript/jquery is that I am currently very weak with them and wouldn't even know where to put the js files or what to name them.
<%= form_tag new_work_order_path, :method => "get", class: "navbar-form navbar-left" do %>
<div class="form-group">
<%= text_field_tag :client_number, params[:client_number], class: "form-control", placeholder: "Enter client number"%>
</div>
<button type="sumbit" class="btn btn-default">New Work Order</button>
<% end %>

Give each button a value attribute.
<%= form_tag new_work_order_path, :method => "get", class: "navbar-form navbar-left" do %>
<div class="form-group">
<%= text_field_tag :client_number, params[:client_number], class: "form-control", placeholder: "Enter client number"%>
</div>
<button type="submit" class="btn btn-default" value="new">
New Work Order
</button>
<button type="submit" class="btn btn-default" value="search">
Search
</button>
<% end %>
Then in your controller method check the params[:commit]:
if params[:commit] == "new"
# create the new WorkOrder
else
# do the search for existing WorkOrders
end
You may want to use a different controller method name since it will be handling both search and new instead of just new.

You should have two different actions for every method(new and search), this for REST good practices.
And for this, you could use other rails form way and set the action for every button like <%= button_to 'Call Action', action_path, method: [POST|GET]%>

Related

Rails - Simple Forms - undefined method `model_name' for nil:NilClass

I am trying to make a form where you select tables that you want to export. I made a simple form with a list of tables that can be exported. My plan was to allow the user to toggle check boxes for the tables they want to export and as a result they would be able to download a zip file containing the tables.
Currently, when I try to go to the page with the form, I get an error:
undefined method 'model_name' for nil:NilClass
The majority of the usage of simple forms that I see online consists of using forms to create new items to save in their models. As a result, it seems that the line simple_form_for #example would mean that when the user clicks the submit button, there is a line in the controller such as #example = SomeClass.new". My understanding is that the user input of the form is saved in #example and can be used by the controller. However, as I am not creating a new item in the model, I just want to use the values from #example, I am not sure what to put in the controller to get rid of the error so that I can code the rest of the function in the controller.
Controller:
class FormController < ApplicationController
def index
#options = []
print(#options)
end
end
The form used:
<h2>Which tables do you want to export?</h2>
<div class="well">
<% tables_in_model = %w(Table1 Table2 Table3) %>
<%= simple_form_for #selected_options, :url => form_index_path, :method => :get do |f| %>
<%= f.input :options, as: :check_boxes, collection: tables_in_model %>
<%= f.button :submit, as: :Submit %>
<% end %>
</div>
As you said correctly in your question, simple_form should be used to render forms to the user when her actions are related to the creation or edition of ActiveRecord models.
For instance, when writing down code to enable a search feature, where your goal is to simply pass a bunch of user chosen params to a controller, you should not use it. I believe you are in a similar position with the feature you described.
Simple solution though: use rails form related DSL to get your form going!
Hope it's the answer you needed. Feel free to ask for more details if needed. Cheers!
i think you are using simple_form you need to specify like
#selected_options = SelectedOptionModel.new(params)
into your controller
then it passes into View.
if you don't have any model you can use form_tag
like this:
<%= form_tag("/search", method: "get") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
this will create html form like this:
<form accept-charset="UTF-8" action="/search" method="get">
<input name="utf8" type="hidden" value="✓" />
<label for="q">Search for:</label>
<input id="q" name="q" type="text" />
<input name="commit" type="submit" value="Search" />
</form>

rails Initialize new object through associated search

In my rails application I would like to be able to search for a client from the nav bar and have it automatically provide the WorkOrderController with the associated client. The goal is to automatically generate some of the work order information before the user gets to the new view. I was hoping to do this by making the new work order path nested under clients, but I'm not sure where to turn the form submission into a find to return the client for use in the work order controller. Clearly I am missing a method somewhere, but I'm not sure where to put it and what exactly it is I need it to do.
As far as I can tell what I need to do is somehow have the form submit to some method, which would then redirect to the new work order page with the :client_id in the params.
Am I totally off base here or am I missing something relatively small? An hour and a half of searching didn't turn up much as most guides talk about the form_for functionality. This doesn't appear to be a full on search either.
#routes.rb
....
resources :client do
get 'schedule', to: 'work_order#client_schedule'
get 'archive', to: 'work_order#client_archive'
resources :work_order, only: [:new]
end
.....
#application.html.erb
.....
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Enter client number">
</div>
<button type="sumbit" class="btn btn-default">New Work Order</button>
</form>
.....
#WorkOrderController.rb
....
def new
client = Client.find(params[:client_id])
#workorder = WorkOrder.new(client: client)
end
....
EDIT:
I made the following change and now when I attempt to load the page I get an error saying I am missing the client_id parameter, though I thought that is what I'm looking for in the first place
<%= form_tag new_client_work_order_path, :method => "get", class: "navbar-form navbar-left" do %>
<div class="form-group">
<%= text_field_tag :search, params[:search], class: "form-control", placeholder: "Enter client number"%>
</div>
<button type="sumbit" class="btn btn-default">New Work Order</button>
<% end %>
EDIT 2:
Was able to achieve my desired result by doing the following:
In work_order_controller.rb
....
def new
client = Client.find_by(clientnumber: params[:client_number])
#workorder = WorkOrder.new(client: client)
end
....
I switched the routes so that the new route was not nested under client and then changed the form to be:
<%= form_tag new_work_order_path, :method => "get", class: "navbar-form navbar-left" do %>
<div class="form-group">
<%= text_field_tag :client_number, params[:client_number], class: "form-control", placeholder: "Enter client number"%>
</div>
<button type="sumbit" class="btn btn-default">New Work Order</button>
<% end %>
I get the impression that I've created some other problem I don't yet see though, but I could just be paranoid
Scanning your code quickly, I don't see anything missing and while there's a number of ways to get this done, I think you're on the (a) right track.
Building things like this in Rails involves getting quite a number of components all working together at the same time, so in this case I'd focus on each step in turn (chronologically) to verify that it works as expected. Specifically I'd:
Watch the Rails console when I click that "New Work Order" button to verify that the client_id parameter is "seen" by the controller. (On closer inspection, according to your HTML, I don't see how this form would pass this parameter... or how the form would submit in the first place. Where's the form's action attribute?)
Use puts statements in the controller #new action to verify that the client object is initialized properly and that #workorder.client_id is the expected value.
Add output to the #new view template that prints out the #workorder.client_id to verify that the ID is carried over to the view. I don't see this view template in the above code snippets so I don't know what you expect to show up.
And so forth. Just breaking the problem into smaller steps so they're easier to figure out what's happening. Good luck!

Substitute a Rails form submit button by a Bootstrap icon

I have an app in which users and groups are linked by a many-to-many relationship.
I have a join table GroupUsers, and I would like to enable an user to add or remove a group from his directly in the group index, which is displayed as a table.
To add a group, I have added a form in one of the column of the index that creates a GroupUser entity. The problem is, I would like to use a Bootstrap icon-plus-sign to submit the form (the user_id and group_id are in hidden fields).
My column looks like this (in slim, . is substitute for class= in HTML parts) :
td
= form_for #item, as: :group_user, url: "groups/#{group.id}/users" do |f|
= f.hidden_field :user_id, :value => current_user.id
= f.hidden_field :group_id, :value => group.id
.form-actions
= f.submit '' do
i.icon-plus-sign.icon.icon-large
For the moment, instead of only a plus sign I get an empty button in the table, what shall I do ?
PS: I've checked this answer: Add icon to submit button in twitter bootstrap 2, which includes a bootstrap icon inside the button, but I want to have the icon instead of the button.
As mentioned by bronislav you won't be able to submit your form without having a button. If you only want to display an image then i think in your case it'll be better to use an image of + icon and then you can use rails image_submit_tag. You can have
= f.image_submit_tag("icon.png")
# => <input alt="Login" src="/images/icon.png" type="image" />
For more information refer here
OR
You can do something like from here:
=button_tag(type: 'submit', class: "btn btn-primary") do
%i.icon-plus-sign.icon.icon-large
With HAML you need to do something like this:
= button_tag(type: 'submit', class: 'btn btn-success') do
%span.glyphicon.glyphicon-search{"aria-hidden" => "true"}
or with ERB
<%= button_tag(type: 'submit', class: 'btn btn-success') do %>
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
<% end %>
The submit button needs to be a button[type=submit] with the icon inside of it. <input type=submit /> elements cannot have node children, and therefore you cannot have an <i> element inside of it.
The HTML should look like this:
<button type="submit" class="btn btn-primary">
<i class="icon-plus-sign icon icon-large"></i>
</button>
EDIT: In slim, I believe it would look like:
= content_tag :button, :type => 'submit', :class => 'btn btn.primary' do
i.icon-plus-sign.icon.icon-large

Bootstrap Popover and Rails

Okay so this question has to do with the proper syntax for html.erb code. What I'm trying to do is use a popover button to display a form. I am able to make a button through the button_tag function, and I am able to make the form from the form_tag function, but I am not able to embed one inside the other. I'm not even entirely sure that this is something I should be doing at all. My understanding was that best practices is to avoid using html when you can use erb to do the work of generating the page.
Anyway, here is the code I have thus far:
<%= button_tag "Remove Friend", :title=>"Remove from Friend List",
:id=>"removeFriend", :class=>"btn btn-default", :rel=>"popover",
:data => {:html=>"true", :placement=>"top", :content=>
"form_tag(\"/friend\", method: \"post\") do
label_tag(:symbolInput, \"Enter Username\")
text_field_tag(:symbolInput)
submit_tag(\"Remove\")
end"}%>
So what this does is generate the following HTML
<button class="btn btn-default" data-content="form_tag("/friend",
method: "post") do
label_tag(:symbolInput, "Enter Username")
text_field_tag(:symbolInput)
submit_tag("Remove")
end" data-html="true" data-placement="top" id="removeFriend"
name="button" rel= "popover" title="Remove from Friend List"
type="submit">Remove Friend</button>
So essentially it just literally copied the erb code as text into the popover.
I have also tried framing each line with <%= %>, but I am very unclear on what the syntax for this would be, or when you should do that.
Basically what needs to happen is that the erb for the form has to be translated to html, which will then be passed to the :content section of the button_tag.
Should I be doing this in this way, or is there some other method to accomplish what I am trying to do? Being new to rails, I'm not sure what the best practices are.
By the way, if I use html to code either the form or the button and erb for the other one, it works perfectly, so there is a work around.
The minute you are inside the Embedded Ruby Tags eg <% %> then everything you do inside here is just ruby or to say it another way must be valid ruby, can be any ruby.
The first refactoring I would do is to move all that content code out own it's own. This halfway point is tidier and should give you a better idea.
<% remove_friend_form = "form_tag(\"/friend\", method: \"post\") do
label_tag(:symbolInput, \"Enter Username\")
text_field_tag(:symbolInput)
submit_tag(\"Remove\") end" %>
<%= button_tag "Remove Friend", :title=>"Remove from Friend List",
:id=>"removeFriend", :class=>"btn btn-default", :rel=>"popover",
:data => {:html=>"true", :placement=>"top", :content=> remove_friend_form }%>
After you isolate the content it becomes more obvious that the 'remove_friend_form' could be isolated even further. To do this move this content into it's own partial.
# create new file in the same folder as the current view.
# _remove_friend_form.html.erb
<%= form_tag("friend", method: "post") do |f| %>
<%= f.label_tag(:symbolInput, "Enter Username") %>
<%= f.text_field_tag(:symbolInput) %>
<%= f.submit_tag("Remove") %>
<% end %>
The main page now looks like this
<%= button_tag "Remove Friend", :title=>"Remove from Friend List",
:id=>"removeFriend", :class=>"btn btn-default", :rel=>"popover",
:data => {:html=>"true", :placement=>"top", :content=> (render partial: 'remove_friend_form') }%>

Rails form updating itself as it's filled out?

I'm trying to make a dynamic form, where the names of some forms at the bottom are based off the values of some forms at the top. For example...
At the top of the page there would be two dropdown menus. At the bottom of the page, there would be two radiobuttons. The name of the first radiobutton would have the name of the first dropdown menu choice, and the second radiobutton would have the name of the second dropdown menu choice.
This is what I have so far:
<%= simple_form_for(#game) do |f| %>
<%= f.error_notification %>
<center>
<div class="form-inputs">
<%= choices = options_for_select( Team.all.map { |team| team[:name] } ) %>
<p>Team 1:</p>
<%= f.select :first_team_name, choices %>
<p>Team 2:</p>
<%= f.select :second_team_name, choices %>
<p>Who you think will win</p>
<%= f.text_field :user_guess %>
</br>
<%= f.submit "Simulate!", class: "btn btn-large btn-primary"%>
</div>
</center>
<% end %>
The text field would be replaced by those radiobuttons instead of a text field.
How do I access the value of the dropdown menus before submitting the form?
For a more comprehensive answer, I'd recommend watching the railscasts episode on this topic, but you'd need a pro (read: paid) subscription.
Since you're not doing anything super complex, you could do it quick & dirty with some javascript:
$(function(){
$('select').change(function(){
html = ''
$('select').each(function(){
html += $(this).val() + '<input type="checkbox" name="game[user_guess]" val="' + $(this).val() +'"/>'
})
$('div.user_guess').html(html)
})
})
If you're pasting the code directly in, you'll need to add a div in your view as well:
<p>Who you think will win</p>
<div class="user_guess"></div>
Don't feel good building HTML with javascript? You can make the change() handler make an ajax call that will load server-generated HTML, which can be made with proper form helpers and such. But for such a simple task it seems like overkill.
(Also, be aware that if the team names can be user defined, this javascript may open you to script injection attacks, so sanitize as needed.)
note that if you want the form to change upon user interaction without the user actually having to submit the form before it changes (rebuilding the page and reloading the view), you have to use javascript. I think. There might be funky things you can do with CSS but that would be really obnoxious to implement.

Resources