I have models for Products and Statement_Sales and want to perform various Sum and Group actions for presenting sales reports and basic analytics in my views. Where is the best place to put these, Model or Controller, and how do I then access them in my views?
At the moment I can easily bring in line by line sales date using something like this in my view:
<% #product.statement_sales.each do |sales| %>
<td><%= sales.units %></td>
<% end %>
But this is line by line data, I want to be able initially give a total by date, then totals for 7 days, 1 Month, 3 Months, 1 Year etc etc.
In console i've figured out grouping by date using:
p.statement_sales.group(:date).sum(:units)
Not sure how to bring that into the app and take it beyond grouping by one date.
Fairly new to Rails (after years of PHP) so hitting a few walls with the differerent approach. I'm sure this is actually quite easy!! Thanks in advance.
The rule of thumb is "fat model, skinny controller". This means you should push most of your logic into the model and keep the controller actions as simple as possible.
For you particular scenario, you will want to look into Rails scopes. Scopes allow you to encapsulate and reuse a complicated query such as the ones you describe above. For example, assuming you have a StatementSale model that belongs_to a Product (I don't know the specifics of your object graph):
class StatementSale < ActiveRecord::Base
scope :units_by_date, group(:date).sum(:units)
end
This would allow you to call #product.statement_sales.units_by_date in your view.
You can also build a scope that takes a parameter. For example, say you wanted to be able to pass in a parameter to group by dynamically, your scope would look like this:
scope :units_grouped_by, lambda { |p| group(p).sum(:units) }
Without knowing the details of the more complicated queries that you'd want to perform, scopes are definitely the place to house all of that logic.
Related
Currently I am building a homepage for my local soccer club and I want to save training times for each team. The training times will look something like this:
Tuesday 18:00-19:30
Thursday 18:30-20:00
What is the best way to store these values inside the database in rails?
I recommend creating a Practice model, with each practice having a :start and :end attribute, each typed as a :datetime. If you generate a migration like so:
rails generate model Practice start_time:datetime finish_time:datetime
That will build a migration for your database, adding the columns you need. Be sure to run rake db:migrate to update your development database.
You would also have to link this new model to your Team model. The relationship between teams and practices seems to be one-to-many, so you'd add this to your Team class
class Team < ActiveRecord::Base
has_many :practices
end
and add the corresponding relationship to your Practice model
class Practice < ActiveRecord::Base
belongs_to :team
end
(Note the different use of singular and plural class names in these methods.)
You might then build a method within your Practice class to render a formatted date and time range from these two attributes.
def practice_time
formatted_str = start_time.strftime("%A %H:%M") + " " + finish_time.strftime("%A %H:%M")
end
You can see more options for the strftime method here
Once you have stored your date information in a logical way, feel free to develop model and/or helper methods to return your data in a more useful form. You might also consider some add-ons like ActiveAdmin to make entering and searching for dates easier.
Here's my solution(may or may not sounds good to you). Create two time columns each represents From and To timings of a day.for example
for Monday it goes like this in your database
|monday_from(time property)|monday_to(time property)|and so on
+--------------------------+------------------------+
Hope this helps you.
Edit: I considered that the training events are repeated in time regularly, so you don't have to stick to a particular date.
You can simply save it to the database as a string.
You can also make a new model (or table) with attributes, start time and end time. Then you can save a Time object to the database.
When loading these Time objects, you can create a helper for view to format the time. It can look the following:
def format_time(time)
time.strftime("%A %H:%M")
end
I'm building an application that is based on a calendar and (with basic functionality expected from a calendar).
As the calendar will have such a fundamental part of the application I don't want to rely on any gem but build the calendar myself.
I don't know which route to go: to have a day-model representing each day with a unique record (that events can reference by day_id) OR render the calendar "on the fly" based on a Date class (and events would then reference the date).
In short: What model design would be the most efficient to render a calendar?
You don't need to have a model at all. The following code below will do the trick.
Grab the code from https://gist.github.com/RichIsOnRails/5535564 and drop it in a helper, use like so (haml below, so adapt it to meet your own needs.) Note that i'm rendering events in this calendar, but you don't have to.
= calendar #date do |date|
.text-left=date.day
- if #events_by_date[date]
- #events_by_date[date].each do |event|
.event=event.title
I will do an article on my website in the near future that goes over this in detail. Good luck!
Unless there is something specific about the days you would like to model, you may be able to just have an events model, with each event having a date field. This approach is simpler and I think preferable. Since there are a practically infinite number of dates, one big advantage of this approach is that you won't need to manage all the logical inconsistencies of keeping a finite subset of dates in your database.
Even if you find a need for a day model, you can do this without tying the model to the database, and thus avoid having a record in your database for every possible date. This might be useful if you want a method that tells you if a day is a work day, or if you want to find a collection of days. For more on how to make a model that doesn't require a database table behind it, see this stackoverflow question: Tableless model in rails 3.1
In one of my tables (sellers), all the fields requires permission from the user for others (registered or non-registered) to see. I could go through and create an associated column for each column, ex. (column1, column1_privacy, column2, column2_privacy). However, this seems redundant and bad design.
Is there a more elegant solution for this in Rails? Thanks in advance.
I wouldn't call it redundant or bad design. If you want per-column access control then somewhere you're going to need one flag per column; you can pack all those flags into one serialized structure but then you'd be fighting against your relational database:
What happens to your serialized ACLs when you add or remove a column? Do you regenerate them all or do you just accumulate cruft?
What happens if you need to include the flags in a query? You're going to have a hard time unpacking your packed flag-blob in SQL and doing the unpacking in Ruby could be very expensive.
You could use a separate EAV-style table that contains column names but you'd still have to clean it as you add and remove columns. And querying with an EAV table tends to turn into an ugly mess quite quickly.
One flag-column for each access controlled column is easy to set up, easy to query, easy to edit, easy to automatically build forms for, and makes it easy to not make a mess in your database. The extra columns may make your tables a little on the wide side but I wouldn't worry about that too much.
The extra columns make it easy to extract the displayable information from your model:
def viewable_parts
%w{column1 column2 column3}.each_with_object({}) do |col, h|
h[col] = self.send(col) if(self.send(col + '_privacy')
end
end
Then you can say things like this in your controller:
#display_info = model.viewable_parts
and your views don't have to worry too much about the access control, they can just show what's in the Hash. This trick can, of course, be used with the other implementations but it is dead easy if you use your "privacy column" idea.
You could create a associated model named SharedColumn
rails g scaffold SharedColumn name:string, seller_id:integer
Seller:
has_many :shared_columns
SharedColumn
belongs_to :seller
Then you may use the column_namesmethod for iteration of a list of checkboxes like this
Controller
#blacklisted_columns = [id, other_non_pubic_column]
View
<% Seller.column_names.each do |column_name| %>
<% unless #blacklisted_columns.include?(column_name) %>
#Generate your checkboxes and labels here
<% end %>
<% end %>
I am considering developing an application using Ruby on Rails that is a planner of sorts. I would like to give a user the ability to see a list of days, click a particular day, and then add things like: Meals, Expenses, Events, Todos, and Exercises. Really I am doing this for me and my growing family.
I am curious with how best to implement this. I can certainly see that Meals, Expenses, etc. need to belong_to :user but I am curious how to implement the belongs_to :day or something like that. Using the created_at or updated_at wouldn't necessarily allow me to provide views for future dates.
I can see how if I created a Days table and then added days through a time and date field that this would work but seems a little strange to ask people to create the actual days.
Or perhaps instead of that I could just create links to variables that search for #today, #tomorrow, but that would get messy.
I have browsed for gems/plugins but can't find one that works. Ideally a person would be able.
Anyone have any thoughts on how to implement something like this?
There are a number of existing Rails calendars, such as http://github.com/elevation/event_calendar or http://github.com/topfunky/calendar%5Fhelper.
However, to answer your specific question about dates: I don't think there's any need to have Day as a model; simply give each event a start date and time, and an end date and time. Remember that Ruby makes it easy to search based on ranges, so "give me all of the events next week" is a cinch if each event has dates and times associated with it.
I'll give it a shot...
Two tables; users and events. A user has many events and an event belongs to a user. Meal, Expenses, etc. are various types of Event. Within events, you can have fields for start and end time of the events. If needed (lets say an events last over multiple days), you could remove the day/time when events occurs into it's own table.
This way, when displaying the calendar for a user, you can find all the events for that date. If none are found, then display nothing.
What do you think?
I would add a model called "Events" and have a properties of the model to represent start date/time, end date/time. I do not think you need a Days model, you can generate your calendar view from the Date class built into ruby.
I have done same kind of project for the Event management in training institute. At there I used event_calender plug in with rails. (enter link description here)
In there we just need to create Event model only. Then we can easily work with that.
I have a design question. Hope this doesn't come across as a lazy attempt.
I'm writing a simple accounting application: A ledger has many accounts, each account has many transactions, and so on.
Double-entry accounting dictates we match transactions with other transactions, so I have a separate model called LedgerItemGroup, which has many transactions.
Very simplistically, we can consider a transaction matched if it belongs to a LedgerItemGroup and the sum of the totals of all transactions in that group is equal to zero.
So far, so good.
My question is what the best approach would be to design the edit_ledger_item view for an unmatched transaction so that the bookkeeper can manually match it with one or more other unmatched transactions.
Here's an (incomplete) layout of the models involved:
class LedgerAccount < ActiveRecord::Base
has_many :ledger_items
end
class LedgerItem < ActiveRecord::Base
belongs_to :ledger_account
belongs_to :ledger_item_group
def matched?
!self.ledger_item_group_id.nil?
end
end
class LedgerItemGroup < ActiveRecord::Base
has_many :ledger_items
def reconciled?
self.ledger_items.inject(0) { |sum, i| sum + i.total_amount } == 0
end
end
This seems to call for a string query input box, plus something to delimit the data range, which then would dynamically yield a list of possible matches. The bookkeeper than adds one or more to a cart of sorts. When checked out, this constitutes the LedgerItemGroup.
A simple multiple select box populated with a collection of unmatched transactions here is out of the question as we can easily have hundreds or thousands at hand.
I do not want to reinvent the wheel here. Is the best approach a checkout cart? Any pointers, suggestions would be appreciated.
The app itself is here should you wish to see more of the code.
I believe multiple select boxes are like the express lane in a grocery store. 8 items or less.
Have you considered pages of check boxes for unmatched ledger items?
Break them up into divs containing a reasonable number of check boxes at a time, say 50. Make sure that all checkboxes across all dives are part of the same check box array. Render them all at once but give all the pages a classes based on their visibility. Then add some javascript pagination, a list of link to function that removes the visible class and adds it to the page associated with the link.
CSS:
.invisible{
display:none;
}
Generated HTML
<div id="ledger_items_page_1" class="visible">
First set of checkboxes
</div>
<div id="ledger_items_page_2" class="invisible">
Second set of checkboxes
</div>
pagination example.
<%= link_to_function("page 3",
"$('.visibile').removeClassName('visibile').addClassName('invisible');
$('ledger_items_page_3').removeClassName('invisible').addClassName('visible');") %>
It wouldn't hurt to display a list of selected ledger items to a list updated onchange for each of the checkboxes, this provides away of reminding the user what they've selected if the ledger items they've checked are not on the current page. Something that works like the way StackOverflow lets you manage your interesting tags question filters.
Given the heavy reliance on javascript you would have deny noscript users from using this action or make find another way to display things.
At the end you submit your form as you usually would.
N.B.: The W3C standard is unclear on submitting form elements with display:none. But as far as I know, all of the major browsers support this behaviour.