I am building an Invoicing application where an Invoice can have various Items.
In the invoice view I have a row like this for every item:
<%= f.text_field :price %>
<%= f.text_field :quantity %>
A new item can be added to an invoice using Ajax, i.e. without resubmitting the page.
This works pretty well.
It would be nice, though, if the total of all the items would get updated through Ajax as well, without the user having to resubmit the page every time.
Can anybody tell me how this can be done?
Thanks for any help.
You should considering using some kind of front end MVC or MVVM framework to handle this. Take a look at knockoutjs:
Simplify dynamic JavaScript UIs by applying the Model-View-View Model (MVVM) pattern
http://learn.knockoutjs.com/#/?tutorial=collections <-- this tutorial shows almost exactly what you would be after.
Basically, you would setup a viewModel that would represent your view which would have a collection of line entries, this would be "observable" which means in knockout language whenever it is changed (added to or deleted from) your binding to it would be updated. For example it could be a with 's bound to each line item.
Then you can have a calculated observable which would update automatically
It depends on your existing code. Do you submit / receive data in JSON format? Try to use some kind of client-side processing (plain javascript, jQuery or other framework).
Or you use more traditional Rails :remote form with js.erb templates? If so, you can update the invoice total in the create.js.erb . Something like (I assume the invoice total is wrapped with a tag with id="total", item belongs_to invoice, invoice has total field)
... # your current code
$("#total").update("<%= escape_javascript(#item.invoice.total)%>");
Same for delete and update actions.
Related
I'm junior RoR programmer.
I know that Ruby language has a calculate method, When I type this in rails console: ModelName.average(:something),it calculates the average value from field :something. It works, but how to add average value to the view?
I have a Items catalogue. Every item has a Review which include rating (integer).
How to display on the view (i.e. show.html.erb) the average value from all rating fields in Review model?
There are multiple ways of doing this. Easiest way is exposing it as a state on the controller, which is the #average, which can then be accessed in the view. As easy as it might be, I don't recommend this approach.
What I do recommend is, adding a method on your model,
model_instance#review_ average and when you are exposing (using the #model_instance) the instance of the model in the #show action of your controller to the view, you can just call #model_instance.review_average
What is the advantage of the second approach? It hides the logic from the view and controller, and pushes it into the model, which in turn makes it easier to write an automated test case.
for implementing average, check: How do I create an average from a Ruby array?
I'm also guessing that you have a has-many relation. It should not be too difficult to do the above.
One thing that you have to also keep an eye for, is n+1 queries, But this becomes an issue only when you have to show the avg in the index page.
Simply add the following to your show.html.erb :
<%= #model.average_rating %>
RESOLVE STEP BY STEP:
first step: Add to your model controller, to def show:
#rating = Model.where(:model_id => params[:id]).average(:attribute).to_i
second step: add to your model view to show.html.erb:
<%= #rating %>
model_id = your model, i.e. Post will be :post_id
:attribute = your attribute, i.e. :rating
It's all.
I'm trying to make a small app in rails where investors can see their balances. The balances are updated by an admin.
The investors are all in a Model called User - is there any way to set up one form in one view where User.balance can be updated for all Users?
The fields in the view can be populated using a <% User.each do |u| %> loop, I guess, but how can I handle the data in the controller?
Thanks!
It might be convenient to implement this in an index view, by using an Ajax-capable gem such as best_in_place, which would let the values be edited in place without the form being submitted.
I'm making an application that involves booking appointments for users. I have a User model and an AvailableDate model. The user has_many availble_dates and the AvailableDate belongs_to user.
I want to present a form for the user so that they can mark a couple of dates in a calendar and each of the dates they mark will become an AvailableDate object tied to that user.
At the moment my solution is to do all the work that a form_for helper would normally do manually. This involves a lot of javascript and is generally just getting far too messy.
I can't figure out how I should make a form_for tag work when I need to create potentially infinitely many dates. In theory a user could keep marking off dates in the future as available. If I knew how many dates I needed to create for a user, I could do user.available_dates.build, N times. But this doesn't work here.
Can anyone help? It like this problem should be pretty common. Am I designing my application wrong?
One technique is to render the fields for your association once, outside the form.
When the user performs whatever interaction that should create a new set of inputs you use javascript to clone the initial set of fields and insert them into the form. The one thing you need to do is change the name of these inputs so that they are unique. Usually people use the current time in milliseconds for this unique identifier.
Been there & have found several resources to help: Tutorial & Cocoon
The bottom line is you need to ensure child_index is unique for each field. The tutorial I use has child_index: Time.now.to_i to create a truly unique id, consequently allowing you to add as many fields as you want
The best way to do this:
Render fields_for as a partial (passing your form builder object)
When you want to add new field, create ajax_field action
Make ajax_field view have its own form_builder
Both your original & ajax_field forms will call the partial
On front-end, you can use JS to GET new form action & append field to page
I can give you code if you want
I'm trying to use form_for and fields_for in Rails 3 to let me edit two objects (of the same class) on one page, but I'm not having any luck: the second object's HTML input tags come out with the same IDs as the first object's.
The specific situation:
I have a class Card. I'm trying to follow general RESTful patterns for it.
Most Cards stand alone, but a small number of them have a second Card object affiliated with the first one, via the "link" property. (I call these "multipart" Cards.)
I want it to be possible to use the standard Card edit page (views/cards/edit.html.erb and views/cards/_form.html.erb) to switch a Card from standalone mode to multipart mode. I'm using JavaScript to show the second set of edit fields on the form when the user selects multipart mode on the edit page. Therefore, the edit form for every Card needs to
contain the form fields for a second Card, to potentially become the "link"ed Card from the main Card being edited.
The HTML fields for the second Card should be identical to those for the first one. I have a complex pretty HTML layout for my fields and inputs, and I want to keep things DRY and avoid duplicating all that code for the second Card's field.
This turns out to be really problematic. I've tried assorted things like:
<%= form_for(#card) do |outer_form| %>
...
<% [#card, #card2].each_with_index do |card, card_index| %>
<%= fields_for card do |f| %>
This doesn't work because the second object's HTML input tags come out with the same IDs as the first object's. They both come out with HTML <select id="card_rarity" name="card[rarity]">, which seems obviously wrong.
I tried changing the quoted lines to say
<% [#card, #card2].each_with_index do |card, card_index| %>
<%= fields_for (card_index == 0 ? card : card.link) do |f| %>
with the hope that this would then provide HTML names like "card[link][rarity]". (Edit:) But it doesn't: even with fields_for card.link, it still produces form fields with name="card[rarity]". So the page has two inputs with the same name and ID, and discards one of them on submission.
I tried saying
<% [#card, #card2].each_with_index do |card, card_index| %>
<%= fields_for card, :as => (card_index == 0 ? "card" : "card2") do |f| %>
but that didn't work either. The :as parameter seemed to be completely ignored.
Can anyone suggest the approach that I'm missing here? I don't find the official documentation on form_for and fields_for very helpful.
(Edit to add:) In particular, surely there must be a way to edit fields for two different objects of the same class within a single Rails form? fields_for makes it trivial to do this with any number of objects of different classes - but how can it be done for two of the same class?
Many thanks!
You say:
with the hope that this would then provide HTML names like "card[link][rarity]", but the problem there is that Rails calls class_name on the object, and in most cases card.link is Nil. I don't want submission of this form to automatically create a dummy linked card for all cards, which is what I think would happen in this case.
I would pursue this strategy a bit more. In your edit controller action I would add #card.link ||= Card.new to prevent nil access errors; in the update controller action (or in the Card model itself if you want to defer the logic there), make sure that empty "link" cards are discarded.
I have a project I am doing in rails. I want to implement this sort of links
{user} has {action} on {file} in {project}
each of the words wrapped by curly braces are entities in my system (models). how do I implement saving these changes in the project and how do I get all of the changes from the database and display them to the user?
I am using rails 2.3.8 if it matters
example of the links I need to display (image)
There are some plugins available to keep track of activities in models:
https://github.com/grosser/record_activities
https://github.com/linkingpaths/acts_as_scribe
https://github.com/face/activity_streams
I normally use acts_as_scribe, it's the simplest of them.
I would recommend acts_as_audited. It works very well. It saves all your changes on a model in the form of a hash, so using it becomes as easy as
audit = Audit.first #just for example
In your view
<%= link_to User.find(audit.user_id), user(:id => audit.user_id) %> has
<%= audit.action %>
Of course you will have to customize how your messages will finally appear. And of course its better not to use find methods in your view. I've used it here just for illustration purposes.