Rails create a table dynamically considering another table - ruby-on-rails

I'm new to ruby and I'm sorry if I haven't described the issue very well :)
So, I want to know if there is a possibility in Rails for the following:
For example I have a table in which I keep some books. Let's call it Books.
This table contains the following fields: name, nr_of_pages.
How to create a table called Pages which has a number of fields equal to the value from nr_of_pages of a certain book. (the value from the Books' field is introduced by user in "new.html.erb" view)
Books
-----------------------
| name | nr_of_pages |
-----------------------
Pages
-------------------------------------------------
| book_id | page_1 | page_2 | | page_3 | ...etc |
-------------------------------------------------
Of course Pages:
belongs_to :book
And Book:
has_many :pages
And how to fill the second table with data because these two models have different views?

pages would actually be the page content like this:
Books
-----------------------
| name | nr_of_pages |
-----------------------
Pages
-------------------------------
| book_id | page_no | content |
-------------------------------
Then when you create a page, you could say:
Page.create(content: "This is the first page of text", page_no: 1, book: some_book)
Then in your controller you could do something like:
#pages = Book.find(by_some_id).pages.order(page_no: :asc)
This will give you an array of pages to loop through in ascending order, giving you the ability to use an #each loop in your view to display all the pages.

Related

Create line chart grouped by two fields

I'm trying to build a line chart with Chartkick that show the number sales by sellers in days, but I don't know how can I do this.
I'm already showing in a table the sellers name and your sales with this code:
#sales = Sale.where(created_at: DateTime.current.beginning_of_month..DateTime.current.end_of_month)
#sales_seller = #sales.joins(:user).select("user_id, COUNT(sales.id) AS total").group('user_id')
This returns:
+--------+-------+
| Name | Total |
+--------+-------+
| Jack | 10 |
| Kevin | 3 |
| Andrea | 11 |
+--------+-------+
How can I put the sales.created_at in this scenario?
My models
Sales
belongs_to :user
User (seller)
has_many :sales
This should work.
I used num_of_sales as the column in sales which contains the number of sales, you must fix it based on your Sale model:
data = #user.joins(:sales).select('users.name as name, sales.num_of_sales').group(:name).sum(:num_of_sales)
It is grouped by user name, but maybe it is better to group by user_id.
To filter sales, just chain a where method:
data = #user.joins(:sales).where(.....).select(.....
Then you can plot as line with:
<%= line_chart data %>

Sorting multiple models in one view table

I have a model which has various different types of information associated with it.
Opportunity.rb
has_many :notes
has_many :emails
has_many :calls
I currently have 3 tables on the show page where in the controller I call
#notes = #opportunity.notes.sorted
#emails = #opportunity.emails.sorted
#calls = #opportunity.calls.sorted
And display them in 3 tables
I'd like to sort them chronologically so I can get a timeline.
Each one of the models has date, and I want to sort by the date then return the objects in date order.
i.e.
The table goes:
Note | Content | 11-Feb | Bob
Call | Content | 07-Feb | Dave
Email | Content | 04-Feb | Steve
Call | Content | 03-Feb | Dave
Note | Content | 01-Feb | Margaret
I can't work out how I merge those tables in the controller into an object I can use in the view so that I can create a table, sort on the date ("created_at") and still keep everything looking nice and clean.
The simplest way would be to combine the 3 collections into an array and sort it by created_at. In your controller:
#combined = (#notes + #emails + #calls).sort_by {|record| record.created_at}
You can then use #combined in your view to show the timeline.

ruby iteration based on table values

The project:
I'm creating a dynamic reporting system.
Metrics define the purpose of the reported data. For example:
"13 house fires."
The admin will define "house fires" as a metric through one form, the reporters will simply add the "13" through a different form.
However, there's another level: I want the reporting to be verbose across connected data points:
"13 house fires during January affecting 42 individuals (or 16 families) "
The verbage is stored in a table "metrics", the data is stored in a table "metrics_data"
Here's the metrics table from the sample above:
metric_id | parentID | childID | prefix | suffix | program_id
1 | 1 | 1 | | house fires | 1
2 | 1 | 2 | during | | 1
3 | 1 | 3 | affecting | individuals | 1
4 | 1 | 4 | (or | families | 1
The key for the sentence-based organization is the parentID - childID relationship.
Here's the metrics_data table:
metric_id | value | date
1 | 13 | 01/01/12
2 | nil | 01/01/12
3 | 42 | 01/01/12
4 | 16 | 01/01/12
The goal:
I want to organize the view (looping through the parentID) to show the metric verbosely:
Program #1
(parentID: 1): "# house fires during (date) affecting # individuals (or # families) "
(parentID: 2): "# shelters during (date) providing # overnight stays (for # individuals) "
Program #2
(parentID: 1): "# new volunteers recruited during (date) "
(parentID: 2): "# volunteers served # hours during (date) "
The code:
class Program < ActiveRecord::Base
has_many :programs_metrics
has_many :metrics, through: :programs_metrics
end
class Metric < ActiveRecord::Base
has_many :programs_metrics
has_many :metrics, through: :programs_metrics
end
Partial _program.html.erb (for programs/index.html.erb):
<% program.metrics.each do |metrics| %>
<div class="row offset1">
<% program.metrics.each do |pid| %> #how do I loop here based on parentID, sorted by childID?
<%= pid.prefix %>
#
<%= pid.suffix %>
<% end %>
</div>
<% end %>
I know I could split this out into a separate table and define the relationship between parentID and childID between two tables, but it seems overly complex to add another relationship layer.
You should probably treat the "parent" and "child" elements like attributes to Metrics, rather than trying to reuse the same model. An alternative would be to create another model called "Events" or whatever, and these Events are related to programs, and Metrics are related to Events. I would probably create a "Metric Type" as well instead of having a prefix or suffix associated directly with each record.
I think that trying to treat all the Metrics at the same level, and trying to loop through them with parentID and childID to create a sentence is infinitely more complicated than just adding another layer to the relationship.
Hopefully this is enough of a push...

Merging two Tables using Scaffold & Rails (Rails noob)

I am new to coding (never taken a CS class and have a very very minimalist understanding of the MVC architecture) and working on a test project to learn it :-) I want to setup some tables tables:
Table 1:
Table_1 ID | Name | Attribute_1 | Attribute_2 | Attribute_3 | etc
1 | Blah | attribute 1 | attribute 2 | attribute 3 |
Table 2:
Table_2 ID | Skill |
1 | nun_chucks |
2 | bow |
3 | arrow |
Table 3:
Table_3 ID | Primary_1 ID | Primary_2 ID |
1 | 1 | 1 |
2 | 1 | 2 |
3 | 1 | 3 |
And then be able to visualize the data so it reads like:
Name | nunchucks, bow, arrow | attribute 1 | attribute 2 | attribute 3 |
I have used Scaffold to create the MVC for Table 1 & 2 and have the #page for each one respectively. I am not sure how to combine them to create table 3 and then make the data show as I am asking.
Thanks!
This is a good reference for what you're doing: http://guides.rubyonrails.org/association_basics.html
INNER JOIN is what you want which is a database operation.
Take a look in your database servers manual and read up on it.
Essentially it takes two tables, joins them by a given column (for instance, Table_2.ID and Table_3.ID) and spits out a summary of both tables joined leaving out columns that don't match across the tables.
Given your example,
and the following contoller in Rails 3
class SomeController < ActionController
def show
#table_1 = Table1.find(params[:id],:include => :table2)
# Table1 and Table2 are your models
# where table2 would be your has_many_and_belongs_to_many assoc in Table1
end
end
you could write this up in show.html.erb like
<%= #table_1.name %>
<%= #table_1.table_2.map(&:skill) %>
<%= #table_1.attribute_1 %>
<%= #table_1.attribute_2 %>
<%= #table_1.attribute_3 %>

Approach to limit the visibility of data

Ok, suppose to have this db schema (relation):
|User | (1-->n) |Customer | (1-->n) |Car | (1-->n) |Support |
|--------| |---------| |-----| |-----------|
|id | | user_id | |Brand| |Description|
|username| |lastname | |PS | |Cost |
|password| |firstname| |seats| |hours |
|... | |.. | |... | |... |
The table User is generated by Authlogic.
I have 2 registred users, each one has his customers, etc. . With Authlogic I'm able to allow only authenticated users to reach controllers/views. That's fine, that's what Authlogic is made for.
Now I need to be sure that the user#1 will never reach informations belonging to customers of user#2.
In other words:
if the user#1 goes to http://myapp.com/cars he will see the list of cars belonging to customers of user#1
if the car with the id=131 belongs to the customer of user#1, only user#1 have to be able to reach this information (http://myapp.com/car/1). If the user#2 insert in the browser the same link he doesn't have to be able to see this information.
Some people suggested me to create a relation between the user and each db table in order to check if a record is associated to the current_user.
What do you think? What is the best approach/solution?
So you have 2 things:
In index page of cars controller only cars which belong to the current user should be shown.
You want to restrict show pages to the owner.
As for the index i suggest something like:
def index
# find logic
#cars = Car.find(:all,:conditions=>{:customer_id => current_user.customers.collect(&:id)})
# whatever else
# ...
end
And the show page:
def show
# .....
# after the find logic
redirect_to :index unless current_user.customers.collect(&:id).include? #car.customer_id
# whatever else
# ...
end
This approach is ok for most of the cases, however a better approach for performance is to add a user_id column to the costumers table, this is called denormalization but it's acceptable for performance wise.

Resources