RUBY ON RAILS 4.2.3 Calculate average - ruby-on-rails

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.

Related

How can I update multiple rows in a Model using a form in Rails?

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.

How do I create a fields_for a potentially unlimited number of children objects?

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

Rails 3 - modifying an attribute of other model after model.save

Unfortunately I'm probably still too much a Rails beginner, so, even though I thought about and tried different approaches, I didn't get to work what I want and now have to ask for help again.
I have a REST comment vote mechanism with thumbs up and down for each comment. That works fine, each handled with counter_cache to count. Now, based on these thumbs up and down votes, I want to calculate a plusminus value for each comment, thumbs_up-votes - thumbs_down-votes. Although I'm not sure if it's the most efficient way to deal with that, I am planning to have the plus-minus value as an extra integer attribute of the comment model (whereas the thumbs up and down are own models). So, what I basically want is, that when a thumbs_up is saved, the comment's plusminus attr automatically should be += 1, and respectively for the thumbs_down.save a -= 1.
How can I issue such an action from within the thumbs_up controller? Do I need to modify my form_for or is my approach completely wrong?
Is there an after_save callback to deal with an attribute of a different model?
From what you've given, it's hard to tell. But I'd say that if you need to show a comment's "thumbs up" and "thumbs down" independently, store them as fields for your Comment model. Then, just making a helper method in your Comment model to get a comment's rating:
def rating
thumbs_up - thumbs_down
end
Edit:
With your new comment, I'd still say make a helper method rather than a field.
#models/comment.rb
def rating
thumbs_up.all.length - thumbs_down.all.length #or whatever way you want to do this
end
if you don't want to mix two different models with helper methods that don't actually belong to neither of those models, you can use Observers http://api.rubyonrails.org/classes/ActiveRecord/Observer.html
your observer will watch one model and do something

displaying a name from an integer in rails 3

I have a rails 3 app where users select an option from a select input which is stored as an integer. The select input is populated by a :collection with simple_form gem, for a table that I seed. This is working exactly the way that I want.
However, I want to display the name instead of the integer in my views.
Right now I am doing this in the view, which is obviously not a best practice.
<% mfg_num = #product.manufacturer.name %>
<%= "#{ListOfManufacturers.find(mfg_num).name}" %>
So, my question is:
What is the best practice for setting up something so that I don't need to put this logic in my view? Should it be in the controller? Should in be in the model? And how do I do it?
there're couple of solutions to this problem, these are:
use instance variable in your controller and use it in the view, smth like
............
#product.manufacturer
#man_name = ListOfManufacturers.find_by_name(#product)
............
use helper method or method in your model
these're good practice

How can I display data from a related model in a Rails form

I have two models
class Car
has_many :engines
end
class Engine
belongs_to :car
end
In the car form I have a select field where the user can select the engine type. The list might be "1.4L; 1.6L; 2.0L..."
Lets say I want to display additional information from the Engine model when the user selects a engine. This should be displayed on the Car form. This might be e.g. BHP, max revs, ...etc
How do I set something like this up. I guess there are two aspects:
How to display data from the engine
model on the car form without using
a field (this data is not editable).
How to update this data dynamically
when the user selects an option in
the select field.
Can anyone point me towards a starting point for this. I'm a bit lost where to begin.
Many thanks!
If you're working with collection_select in your form, you are setting two arguments, like :id and :name in your collection_select call. :id is the method called to determine the value for the option tag and :name is the method used to display the option tag's content.
Solution: Create a method (e.g. :name_for_select) in your engine model which returns a string with more information about your engine and call collection_select with :id, :name_for_select instead.
This is called a nested form, and if you google that you will find a lot of hints and tips. E.g. check out this and this tutorial.
You should also consider using a form builder like formtastic or simple_form: they have a lot of helpers to make life easier for you.

Resources