Dynamic Fancybox forms in Rails - ruby-on-rails

Can anyone point me towards some simple step by step guides that would help me to understand how to couple Fancybox and Ajax together?
I have three models:
Class Event
belongs_to :site
belongs_to :operator
End
Class Site
has_many :events
End
Class Operator
has_any :events
End
Users can add a new event, and select Site or Operator from select boxes. I've also created a quick-add partials for Site and Operator. These are rendered in a div on the Event form, and displayed in Fancybox when a link is clicked.
<%= link_to_box "Add", "#site" %>
<%= link_to_box "Add", "#operator" %>
<div id="site">
<%= render 'sites/quickadd' %>
</div>
<div id="operator">
<%= render 'operators/quickadd' %>
</div>
So far so good.
Now I have two questions.
1- How to I hide the quick-add divs on the Event form, but display them in Fancybox. CSS classes such as display:none or visibility:hidden result in the partials not displaying in either location. Currently the partials are rendered at the end of the Event form as well as in the Fancybox popup, but this is not ideal.
2- How do I setup these quickadd partials so that they dynamically update the Event form. For example I'm adding a new Event for site Foobar. Foobar is not available in the select box so I click "add", enter Foobar in the popup form, click save, and Foobar is automatically set in the select box on the Event form.
I assume that question 2 will involve Ajax and calls for remote => true. However I'm very new to this and really need a basic step by step guide that would help me understand how to implement this. For example, do the "add" links need to be remote, or the partials? If the partials, how do I code that? After save, how do I update and set the parent form select box?
Like I said, basic stuff, but having read several guides for Fancybox and other lightbox-like popups, and several guides for Ajax, I'm still having trouble tying the two together.
Thank you for any pointers.

1) If it isn't showing and hiding the divs correctly for you, then I would put them as display:none; in the css and use something like this for your fancybox call
$("#site").fancybox({
onStart : function() {
$('#DIV').show();
},
onClosed : function() {
$('#DIV').hide();
}
});
2) When I have a form like your describing, after you are done submitting the form (which I would submit using :remote => true on the form tag, you can have it check for ajaxComplete. and you can set some variables on your create.js.erb or update.js.erb files that will show and hide forms, set the current index, or you might have to reload your list after the ajaxCompleted is "completed"
Not sure if this helps or gives direction, but hope it will give some guidance..might be able to post more later today to help

Related

rails link_to tag to build join record in rails

I'm trying to build a form that allows a user to add products to an order.
The way I have it setup so far is that a user will select from 2 dropdown boxes and type into 1 text field
1 - the product they want
2 - its size
3 - the quantity they want.
What I hope to do is have the user click a link_to tag to "Add" this item to their order.
I was thinking I could do this via ajax and build the associative record in my controller and have it render on the page when the request returns.
When the user is done with their order and hits submit I can create my Customer Order with the products they wish to buy.
Am I approaching this correctly?
e.g. my form has the following:
<%= collection_select :order_line_item, :cake_id, Cake.order(:name), :id, :<%= grouped_collection_select :order_line_item, :cake_size_id, Cake.all, :cake_sizes, :name, :id, :name %>
<%= label_tag :quantity %>
<%= text_field_tag :quantity %>
<%= link_to "Add to order", add_to_order_path, {method: :post, remote: true} %>
Am I approaching this correctly? I then need to be able to add the fields above to the ajax post so I can populate the associative record with the relevant values.
Am I approaching this correctly?
I don't know about 'correctly'. But, I can imagine some alternatives.
Here are some sketches:
One Option:
This approach assumes that the Order is already saved so that you can associate a Product with that order. Perhaps Order has a status.
You could wrap that whole bit (product, size, quantity) in its own form (not embedded within your order form).
Have the form submit via js using remote: true (if you're using Rails 5, then this may be the default behavior).
When the user clicks on "Add", you will receive the field values as parameters in your controller where you can associate the Product with the Order.
Then, render back an HTML blob that can be inserted into the DOM (perhaps an order row?)
Use js to insert the blob and clear the form.
Another Option:
You could leave that whole bit (product, size, quantity) as not a form and have it reside outside your form.
Wrap it all up in a div.
Convert that link into a span or something similar.
Attach an .on 'click' event (I'm assuming jquery, you don't specify, so I'm going to run with it) to the wrapper.
When the link is clicked, the click event will bubble up to the wrapper.
Have the wrapper submit the field values via ajax.
Proceed as above.
I wouldn't really recommend this approach as it seems to me that you're basically replicating the functionality of a remote form. But, there is...
Yet Another Option
This approach does not require that the Order already exists.
You could have a hidden order item row outside of your form.
You construct your page as above in Another Option.
Now, when the user clicks the "Add" button, clone the hidden order item row.
Fill in the cloned order item with the appropriate values.
Insert the cloned order item into your Order form.
When the user clicks "Order" or "Submit" or whatever they click when they're done, you'll get all of the order rows as field sets.
Process the order line items along with the form. (Some folks might suggest accepts_nested_attributes_for, but I never use that.)
I suspect there are others. Or perhaps variations.

Rails - Submit multiple forms on same page

Model:
Users have expenses. Expense has a status.
View:
As users add their expenses, they are shown in a list. Each expense row has a form button on the end, which is used to submit the expense (changing the status of the expense). This allows users to add expenses they have not completely filled out, and submit them when they are ready. There is no parent form on this page, just the form buttons which submit the expense to a method which changes the status, and then reloads the page.
Currently it works great, but users have asked to be able to "submit all" the expenses that are showing on the view with a single button.
Question:
What is the proper way to handle this in rails? Should I find a way to gather the array of expense id's and then submit a separate form? Is there a way to ask for a set of records present in a view with a certain status?
Thanks!
Another option, if I'm thinking about this right (big if), would be to wrap your page in a User form. Then you could have something like...
<%= form_for(#user) do |f| %>
<% #user.expenses.each do |expense| %>
<% f.fields_for expense do |e| %>
<!-- expense form -->
<% end %>
<% end >
<% end %>
This is something you could submit as a whole. I'm having trouble picturing what a single expense addition might look like, but hopefully this gets you a little further down the road.
Edit: in addition to having this User form on the page, you could have an "extra" Expense form to create an expense. When you submit a new expense, that expense appears in the list under the user form, where it can be edited or submitted, either as part of a group or individually (as part of a "group" of 1).
custom controller action:
def update_all_expense_statuses
expenses = current_user.expenses
ExpenseUpdater.new(expenses).update_expense
redirect_to :back
end
expense updater class:
class ExpenseUpdater
def initialize(expenses)
#expenses = expenses
end
def update_expense
#expenses.each do |expense|
expense.update_attributes(status: 'paid')
expense.save
end
end
end
This is just an example of one way to update all the user's expenses with a custom controller action. Just call the controller method from a link_to:
<%= link_to "Update all expenses", update_all_expense_statuses_path %>
Remember to add it to your routes. Hope this helps.
The first thing you should do is change the forms to submit remotely, ie make an ajax request. Then you're not reloading the whole page. Check out Rails' various "remote" form helpers, eg "remote_form_for".
Then, write a javascript function to submit all the forms for inputs that have changed since the page loaded. You'd probably want to add a "changed" (or similar) class to the parent form in an onchange event in each input, to facilitate this. I think this is the best way to handle the "status" thing you're asking about. Make a "Submit all" button which calls this function.
Use a form/service object http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ to encapsulate expense report

How do I add autofocus to a form field if it is the edit form?

I am new to ruby on rails and working through the Rails Tutorial book and also Rails Programming from pragmatic studio. However for my project I need to find solutions now so sad I can't spend more time on the researching.
My question is, once I am able to add, show and edit forms I am being instructed to create partials, ie _forms.html.erb and then rendering those forms on the edit, show and new pages.
On my _forms.html.erb partial, how can I implement some flow using if statements based on the page that the form is being rendered for.
For example, when _form.html.erb is being rendered for the show page I want certain form_for labels/fields to be set to readonly: true. At the bottom of the form I want submit, edit, change buttons based on the page aswell.
So far I am trying to use the parems[:action] == "new" or "edit" etc to implement the control flow as follows:
Old code under the edit.html.erb file:
<%= f.label :patform_type %>
<%= f.text_field :patform_type,autofocus: true %>
New code under the _form.html.erb file:
<%= f.label :patform_type %>
<%= f.text_field :patform_type %>
<% if params[:action] == "new" %>
<%= ,autofocus: true %>
<% end %>
My original code has been influenced by these posts:
Rails not editable text field
How to disable all form_for input fields in Ruby on Rails app?
Once I get this right then I am hoping I can use it to wrap it around other elements like the submit, edit buttons etc or other fields.
Also if someone knows a better way can you please let me know as I don't know what I don't know.
Thanks for any assistance/ideas you can provide.
You probably have to stick with a bunch of if/else statements if you need such depth of logic within the form, but I would recommend having the forms typed into their respective erb file, and not be rendered from a partial with a ton of logic.
A partial is meant for repeated code, and your code is not exactly what I would describe as repeatable. It is also not immediately understandable and will contain code that is essentially a waste of time to read:
For example, if I am reading the edit action's view and I see:
if params[:action] == "new"
It will be testing for an action that isn't even relevant to the current view, unlike logic such as:
if current_user.admin?
which will be more suitable for partial-based logic.
Hope that helps, enjoy RoR

Navigation Indicator for Current Page and Sub-Pages

I have seen similar questions answered but I cannot find exactly my problem and I can't work out how to change the others to make them fit.
I am writing a simple rails 3 app that has 2 main sections. One called Students and one called iConnects with multiple pages for each. I have a simple navigation bar to allow navigation to either by navigating to the first record of either of these sections when clicked. This click also sets a class which has a colour set on it in CSS to indicate which section you are on. This however only works if you click that link once. If you navigate to any of the sub-pages e.g. students/2 the class is obviously not present there and there is no visual indication.
My question is how do I have a persistent class added to the navigation to indicate whether the user is on either students or iConnects?
I have a separate partial in my shared which I am pulling in with this code..
<div id="section_navigation">
<%= link_to 'iConnect', #iconnects.first, :class => current_page?(#iconnects.first) ? "current" : "" %>
<%= link_to 'Students', #pages.first, :class => current_page?(#pages.first) ? "current" : "" %>
</div>
And from my students show.html.erb
<%= render :partial => 'shared/navigation' %>
I am fairly new to rails and so can't think how to do this myself and I am resisting the urge to do it in a Javascript way as I know backend output is the correct approach for this.
Any hints or tips are more than welcome. Thank you for your time...
Use something like simple-navigation

Attaching functionality to a button in rails 3

I have a set of buttons displaying on my webpage. The effect of clicking one of the buttons needs to be that a call is made to an external API (and maybe the response being received, and updating something on the page).
Some additional information: these buttons are placed on the page by a partial, and make up part of a list of users. The buttons are intended to activate and deactivate the users being listed. I'm not sure if this setup will affect the best approach for doing what I want to do, so I thought it would be worth mentioning.
How should this be done? Should the buttons be links to some controller within my rails app? Wouldn't that require the page to be reloaded when the button is hit? Can I offload that request to ajax?, etc.
I don't know the best way to approach this, and any guidance would prove invaluable.
Ok. I believe I have found a good implementation of this.
The trick is to create a form encapsulating the button in order to hit the proper controller when the button is clicked. In my case, I used the rails form_tag function to generate my button within my _list_item.html.erb partial view for my Developer controller as follows:
<div id=<%= list_item.id %>>
<%= form_tag "/Developer/toggle", :method => "get", :remote => true do %>
<p>
<% if list_item.inactive? %>
<%= submit_tag "Activate", :name => nil %>
<input type="hidden" name="act" value="activate" />
<% else %>
<%= submit_tag "Deactivate", :name => nil %>
<input type="hidden" name="act" value="deactivate" />
<% end %>
</p>
<input type="hidden" name="dev_id" value=<%=list_item.id%> />
<% end %>
</div>
There are 2 things that should be called to attention within this partial.
Since this is a partial rendered as part of a list, you want to give each list item a unique id so that your javascript will act on only that element. This is done in the first line, <div id=<%= list_item.id %>>, which I know will be unique because each Developer in the list necessarily has a unique id.
:remote => true is a necessary argument to the form_for function this is what causes the request to be made in the background as opposed to loading a new page.
This form, when submitted hits my the Developer#toggle action with two parameters: act, which is either activate or deactivate and id which is the id of the Developer we are acting on. Both of these parameters are hidden fields within the form.
After the form is submitted, inside of the controller, I just obtain an instance of the correct Developer (in my case, doing so is rather complicated, but in most cases it's probably something like #dev = Developer.find(id)), and performs the steps necessary to activate/deactivate the developer.
Lastly, I created a toggle.js.erb file within the view directory for my Developer controller which gets rendered once the controller has completed its task. This file simply obtains the element (through the unique id we gave it in the partial) and replaces the inner html by re-rendering the partial as follows:
document.getElementById("<%=escape_javascript(#dev.id)%>").innerHTML="<%=escape_javascript(render :partial => 'developer/list_item', :object => #dev) %>";
The result is the partial being re-rendered after the developers active status has changed, resulting in the appropriate Activate or Deactivate button.
I realize that this answer is highly focused on my particular application, especially needing to deal with the toggling of active vs. inactive, however I believe it is easily simplified and adapted to other cases that may require less complexity.
You could do this task with Rails but then page refresh must be done. If you use Javascript/AJAX then page shouldn't be refreshed. Example (jQuery):
$(":button").click(function(){
//Your Code here..
});
EDIT:
Above is jQuery code. What you want to do is some action to happen when you click on button. If you want to call external API then you could use ajax. Look for documentation for POST and GET in jQuery: http://api.jquery.com/jQuery.post/ and http://api.jquery.com/jQuery.get/.
Google for rails jquery tutorial.

Resources