Rails and Chartkick - ruby-on-rails

I'm trying to implement this style chart into my rails project.
<%= line_chart #goals.map{|goal|
{:name => goal.name, :data => goal.feats.group_by_week(:created_at).count }
} %>
I'm currently using Chartkick to do so. http://ankane.github.io/chartkick/
Here is how my tables are set up.
I want to track current_user Timesheets from 3 columns on my Timesheets table.
def change
create_table :timesheets do |t|
t.decimal :teacher
t.decimal :study
t.decimal :conversation
t.date :day
t.references :user
t.timestamps
end
add_index :timesheets, :user_id
end
That is currently what my Timesheet Table looks like. How can I go about tracking :teacher, :study, :conversation through a chart through chartkick? I've read through the documentation, and can't quite grasp it.
Thank you!

If I understand correctly, you want to do:
<%= line_chart [
{name: "Teacher", data: current_user.timesheets.map{|t| [t.day, t.teacher] }},
{name: "Study", data: current_user.timesheets.map{|t| [t.day, t.study] }},
{name: "Conversation", data: current_user.timesheets.map{|t| [t.day, t.conversation] }}
] %>

Related

How do I submit event on f.collection_select, and change the content displayed, dependent on what is selected in the dropdown?

I am creating a webshop with products. I sell digital game accounts.
I have invented a dropdown menu, with f.collection_select, for the user to choose which server the account must belong to.
If the user selects a server, lets say "North America", I want the page to show the accounts which I have that belong to the server "North America". I have set up two models, the server model, this model just contains name:string, and the model has_many :accounts.
Next model I have is account.rb. This model stores all information in regards to account, and belongs_to :server.
I use this form for selection of server, in my views/accounts/index.html.erb
I can see that it works, and shows my servers, which I have created in the database.
<%= form_with do |f| %>
<%= f.collection_select(:server_ids, Server.all, :id, :name, remote: true) %>
<% end %>
class CreateAccounts < ActiveRecord::Migration[6.0]
def change
create_table :accounts do |t|
t.string :name
t.string :password
t.string :BE
t.integer :level
t.integer :price
t.references :server, null: false, foreign_key: true
t.timestamps
end
end
end
class CreateServers < ActiveRecord::Migration[6.0]
def change
create_table :servers do |t|
t.string :name
t.timestamps
end
end
end
This is how the site looks atm with the dropdown:
So here I have selected EUW server. When I change it to NA, I want the page to display the accounts I have in the association Server.find(name:"Europe West (EUW)".accounts
Here is a video, that shows what I am going for:
https://www.youtube.com/watch?v=bZUxS5oMMOw

Simple voting system without a gem - how to track up or down vote and allow one vote per user_id

Any help would be most appreciated. I am less three weeks into my rails journey, thus apologies in advance.
I've written a simple list voting system, a user can up or down vote said list. It works okay. However, I am stuck on two issues:
What is the most efficient way of restricting a user_id to vote once? However, they can then toggle their vote up or down. I began over-engineering a after_touch Callback. Is the best practice to set a has_one :vote in the User model? Does Active Record take care of everything after that?
Is it possible to disable the vote (up or down) button when a user clicked the button. Without adding another database column to track a up or down vote? So they can toggle between up or down voting, after the initial vote cast.
Votes Controller
class VotesController < ApplicationController
def vote_up
#list = List.find(params[:list_id])
#vote = Vote.find_or_create_by(list_id: params[:id], user_id: current_user.id)
Vote.increment_counter(:vote_count, #vote)
redirect_to list_path(#list), notice: 'Voted Up.'
end
def vote_down
#list = List.find(params[:list_id])
#vote = Vote.find_or_create_by(list_id: params[:id], user_id: current_user.id)
Vote.decrement_counter(:vote_count, #vote)
redirect_to list_path(#list), notice: 'Voted Down.'
end
end
schema
create_table "votes", force: :cascade do |t|
t.integer "vote_count"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "list_id", null: false
t.integer "user_id"
t.index ["list_id"], name: "index_votes_on_list_id"
end
excerpt of show.html.erb with relevant up/down vote buttons
<% if #list.votes.any? %>
Count Of Votes <%= content_tag(:p, list_vote_counter?) %>
<% end %>
<%= button_to 'Vote Up', list_vote_up_path, method: :post, params: { list_id: params[:id] } %>
<%= button_to 'Vote Down', list_vote_down_path, method: :post, params: { list_id: params[:id] } %>
Thank you in advance.
This is confusing. You say you want to set User to has_one :vote. But your table seems to be a join table for user_id and list_id. So a person could have ONE vote PER LIST, correct? You can enforce uniqueness but not the way you mentioned.
You don't have your model code for all of the models, but you could make a List model have
has_many :votes
has_many :users, through: :votes
Then Users has
has_many :votes
has_many :lists, through: votes
and the Votes model can have
belongs_to: :user
belongs_to: :list
validates :user_id, :uniqueness => { :scope => :list_id }
That last uniqueness validation would prevent more than one user vote per list from what I understand here: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of

Limit association based on rich relation attributes

first question for me here! Im trying to assign 'key companies' to my users. These are found in a many-to-many rich join table. On this table there are attributes like new, key, active and so forth. I want to assign companies to users in a long list and for that Im using SimpleForm.
Everything is working excepts that I want to filter out and limit the association relation based on the attributes on the rich relation. I have company relations for each user but not all of them are akey-relation or a new-relation for example. I only want the association being key to show up and not touch the other ones. I also want to set the attribute active to true when Im assigning these companies to the users. My code looks like this now:
user.rb
class User < ActiveRecord::Base
has_many :company_user_relationships
has_many :companies, through: :company_user_relationships
company.rb
class Company < ActiveRecord::Base
has_many :company_user_relationships
has_many :users, through: :company_user_relationships
schema.rb
create_table "company_user_relationships", force: true do |t|
t.integer "company_id"
t.integer "user_id"
t.boolean "key"
t.boolean "active"
t.datetime "last_contacted"
t.string "status_comment"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "status"
t.boolean "new"
end
users_controller.rb
def assign_key_companies
User.update(params[:users].keys, params[:users].values)
redirect_to(:back)
end
view
= form_for :user_companies,
url: assign_key_companies_users_path,
html: {:method => :put} do |f|
- users.each do |user|
= simple_fields_for "users[]", user do |u|
tr
td.col-md-4
= "#{user.first_name} #{user.last_name}"
td.col-md-8
= u.association :companies, label: false, collection: #key_company_candidates,
input_html: {data: {placeholder: " Assign key companies"}, class: 'chosen-select'}
= submit_tag "Save key companies", class: "btn btn-success pull-right"
I basically want to only show user.companies.where(key: true) and the SQLCOMMIT to always put the key-field to true when updating the record.
How can i filter out to only affect the associations I want?
I can think of two ways.
First to filter it at the association level
class User < ActiveRecord::Base
has_many :company_user_relationships, -> { where("company_user_relationships.key" => true) }
Or a where
user.companies.where("company_user_relationships.key" => true)
When you call user.companies it actually doing the join table among all three tables, so you could specify the condition like my example.

has_and_belongs_to_many: how to get correct relations? (JSON output)

I have a item model which belongs_to a product model.
Each product has_and_belongs_to_many specification models:
class Product < ActiveRecord::Base
has_many :items
has_and_belongs_to_many :specifications
end
Relations between products and specifications are saved within products_specifications JOIN Table:
create_table "products_specifications", id: false, force: :cascade do |t|
t.integer "product_id"
t.integer "specification_id"
end
Each specification has_and_belongs_to_many tags:
class Specification < ActiveRecord::Base
# Product Specifications (e.g. Color, Weight, Size, Brand, Product-Type)
has_and_belongs_to_many :products
has_and_belongs_to_many :tags # Tags = Spec Detail (e.g. blue, 100 gramm, 5x5x2.5 cm, Apple, Smartphone)
end
JOIN Table for specifications_tags:
create_table "specifications_tags", id: false, force: :cascade do |t|
t.integer "specification_id"
t.integer "tag_id"
end
And also each tag has_and_belongs_to_many specifications:
class Tag < ActiveRecord::Base
# Product Specifications Tag/Details (e.g. blue, 100 gramm, 5x5x2.5 cm, Apple, Smartphone)
has_and_belongs_to_many :specifications
end
I try to output the item's product with JOIN Table related specifications and JOIN Table related tags like this:
def show
item = Item.find(params[:id])
render json: item.to_json(include: {
product: {include: {specifications: {include: {tags: {}}}}}
})
end
This does output the correct product model, but it includes all specifications and all tags within the database, instead of only the related ones. The wrong JSON Output currently looks simplified like this (for an item which belongs to "Apple iPhone 6 Smartphone" product):
"item":{"id":1,"product":
{"id":1,"name":"Apple iPhone 6 Smartphone","specifications":
[
{"id":1,"name":"Product Type","tags":
[
{"id":1,"name":"Smartphone"},
{"id":1,"name":"Smartphone"}
]
},
{"id":2,"name":"Brand","tags":
[
{"id":2,"name":"Apple"},
{"id":4,"name":"Samsung"}
]
},
{"id":3,"name":"Model","tags":
[
{"id":3,"name":"iPhone 6"},
{"id":5,"name":"Galaxy A5"}
]
}
]
}
}
Currently I have only two products in the database: "Apple iPhone 6 Smartphone" and "Samsung Galaxy A5 Smartphone". You can see that it outputs the specifications and tags from all products, instead of only the has_and_belongs_to_many related ones. The correct JSON output for the item related to the "Apple iPhone 6 Smartphone" product would look like like this:
"item":{"id":1,"product":
{"id":1,"name":"Apple iPhone 6 Smartphone","specifications":
[
{"id":1,"name":"Product Type","tags":
[
{"id":1,"name":"Smartphone"}
]
},
{"id":2,"name":"Brand","tags":
[
{"id":2,"name":"Apple"}
]
},
{"id":3,"name":"Model","tags":
[
{"id":3,"name":"iPhone 6"}
]
}
]
}
}
Edit:
The problem has nothing to do with how the JSON is outputted. The real question is:
How can I relate the tags correctly to the respective specifications of the respective product?
It was a (thinking) problem with has_and_belongs_to_many association. I switched to has_many :through associations, and created an extra model/table: "product_specs"
create_table "product_specs", force: :cascade do |t|
t.integer "product_id"
t.integer "specification_id"
t.integer "tag_id"
t.integer "creator_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
now i can easily output the right associations with JBuilder (thanks to #kjmagic13 for pointing it out) like this:
json.extract! #item, :id, :condition, :user, :winner
json.product do
json.extract! #item.product, :name
json.product_specs #item.product.product_specs do |spec|
json.specification spec.specification, :id, :name
json.tag spec.tag, :id, :name
end
end
You should be able to use jbuilder. Something along the lines of:
# app/views/items/show.json.jbuilder
json.item do
json.extract! #item, :id
json.product do
json.extract! #item.product, :name
json.specifications #item.product.specifications do |spec|
json.extract! spec, :name
json.tags spec.tags, :id, :name
end
end
end
Be sure to change item to an instance variable #item in the show method in your Items controller.

How do you seed models with HABTM relationships to other seeded models

I'm working on my first Rails(3) App, and looking to seed a bunch of data.
The issue I'm having is that I want to seed some models that have a has_and_belongs_to_many relationship with other models I've just seeded. I'm doing what seems right, but I'm not getting the results I'm expecting.
I have an Asana model (simplified):
class Asana < ActiveRecord::Base
has_and_belongs_to_many :therapeutic_foci
end
and the TherapeuticFocus model:
class TherapeuticFocus < ActiveRecord::Base
has_and_belongs_to_many :asanas
end
In my db/seeds.rb, I create some TherapeuticFoci:
tf = TherapeuticFocus.create([
{:name => 'Anxiety'},
{:name => 'Asthma'},
{:name => 'Fatigue'},
{:name => 'Flat Feet'},
{:name => 'Headache'},
{:name => 'High Blood Pressure'},
{:name => 'Stress'} ])
Then create an Asana:
asanaCreate = Asana.create!([
{ :english_name => 'Mountain Pose',
:traditional_name => 'Tadasana',
:pronunciation => 'TadaSANA',
:deck_set => 'Basic',
:type => 'Standing',
:therapeutic_foci => TherapeuticFocus.where("name in ('Stress','Flat Feet')")}
])
The result is that the TherapeuticFocus models are created, the Asana is created, but it doesn't create the relationships to the TherapeuticFocus models. The resulting array is empty.
If I run
TherapeuticFocus.where("name in ('Stress','Flat Feet')")
in the rails console, I get the expected two records:
irb(main):010:0> TherapeuticFocus.where("name in ('Stress','Flat Feet')")
=> [#<TherapeuticFocus id: 6, name: "Flat Feet", description: nil, created_at: "2010-10-11 01:48:02", updated_at: "2010-10-11 01:48:02">,
#<TherapeuticFocus id: 19, name: "Stress", description: nil, created_at: "2010-10-11 01:48:02", updated_at: "2010-10-11 01:48:02">]
So, how does one do this?
Or, is there a better way to do this?
Thanks!
POST ANSWER:
I had already added the inflection:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'focus', 'foci'
end
My migration for the join tables looks like:
create_table :asanas_therapeutic_foci, :id => false do |t|
t.references :asana, :therapeutic_focus
end
I'll try changing this to t.belongs_to instead of t.references and see if that works.
Did you register the pluralization for “focus”? It is not defined by default, so you will need to define it (usually in config/initializers/inflections.rb):
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'focus', 'foci'
end
You also need to make sure your migration has defined the correct join table for the HABTM association. Here is the pertinent part of the “up” migration that I used:
create_table :asanas do |t|
t.string :english_name
t.string :traditional_name
t.string :pronunciation
t.string :deck_set
t.string :type
end
create_table :therapeutic_foci do |t|
t.string :name
end
create_table :asanas_therapeutic_foci, :id => false do |t|
t.belongs_to :asana
t.belongs_to :therapeutic_focus
end
I used the models as you quoted.
With those bits in place, I was able to load your seed definitions.

Resources