Rails 4 active record query - ruby-on-rails

I have 2 models, Project and TodoItem. Please see below table structures and Models below.
What I am trying to do query all todo_items where assigned = current_user.fullname and completed_at is nil grouped_by project name and Ordered_by the project name.
Then I want to loop out something similar to this:
PROJECT 1 Name
ToDo_Item 1 content
ToDo_Item 2 content
ToDo_Item 3 content
PROJECT 2 Name
ToDo_Item 1 content
ToDo_Item 2 content
ToDo_Item 3 content
Table Structure:
create_table "projects", force: :cascade do |t|
t.string "name"
t.text "details"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "todo_items", force: :cascade do |t|
t.string "content"
t.string "assigned"
t.integer "project_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "completed_at"
end
Models:
class Project < ActiveRecord::Base
has_many :todo_items, :dependent => :destroy
validates_presence_of :name
end
class TodoItem < ActiveRecord::Base
belongs_to :project
end
Thank you in advance.

For your complete solution
you can try this
#projects = Project.includes(:todo_items).where(todo_items: {assigned: current_user.fullname, completed_at: nil }).group("projects.name").order("projects.name")

You're almost there.
You just need to add .where:
#projects = Project.includes(:todo_items).where(completed_at: nil)

Related

Active Record: How to fetch data from 3 tables at once?

I want to fetch sku_code from products, wh_name from warehouses table and item_count from product_warehouses.
I tried something like
Product.all.includes(:product_warehouses)
But not working :(
Below are the schema of my tables
create_table "product_warehouses", force: :cascade do |t|
t.integer "product_id"
t.integer "warehouse_id"
t.integer "item_count"
t.integer "threshold"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["product_id"], name: "index_product_warehouses_on_product_id"
t.index ["warehouse_id"], name: "index_product_warehouses_on_warehouse_id"
end
create_table "products", force: :cascade do |t|
t.string "sku_code"
t.string "name"
t.decimal "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "warehouses", force: :cascade do |t|
t.string "wh_code"
t.string "wh_name"
t.string "pin"
t.integer "max_cap"
t.integer "threshold"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Below are the relationship between tables:
class Product < ApplicationRecord
has_many :product_warehouses
has_many :warehouses, through: :product_warehouses
end
class ProductWarehouse < ApplicationRecord
belongs_to :product
belongs_to :warehouse
end
class Warehouse < ApplicationRecord
has_many :product_warehouses
has_many :products, through: :product_warehouses
end
If you want to load all three records with a single query, use eager_load:
Product.all.eager_load(:product_warehouses, :warehouses)
Let's say you want to print sku_code, wh_name, and item_count in the console. First load all the products into variable:
products = Product.all.eager_load(:product_warehouses, :warehouses)
Then loop through the records and print out each of the values:
products.each do |product|
puts "sku_code: #{product.sku_code}"
product.product_warehouses.each do |product_warehouse|
puts "item_count: #{product_warehouse.item_count}"
puts "wh_code: #{product_warehouse.warehouse.wh_code}"
end
end

Rails InvalidForeignKey

I am developing a portfolio for my website, I decided to add skills to each portfolio item.
class PortfolioSkill < ApplicationRecord
belongs_to :portfolio
belongs_to :skill
end
class Portfolio < ApplicationRecord
has_many :portfolio_skills
has_many :skills, through: :portfolio_skills
def all_tags=(names)
self.skills = names.split(",").map do |name|
Skill.where(name: name.strip).first_or_create!
end
end
def all_tags
self.skills.map(&:name).join(", ")
end
def remove_skill_tags
PortfolioSkill.where(portfolio_id: id).destroy_all
end
end
create_table "portfolio_skills", force: :cascade do |t|
t.integer "portfolio_id"
t.integer "skill_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["portfolio_id"], name: "index_portfolio_skills_on_portfolio_id"
t.index ["skill_id"], name: "index_portfolio_skills_on_skill_id"
end
create_table "portfolios", force: :cascade do |t|
t.string "name"
t.string "client"
t.date "completed"
t.text "about"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "long_landscape"
t.string "cover"
t.integer "category_id"
t.index ["category_id"], name: "index_portfolios_on_category_id"
end
When I click destroy on the index page I get the
SQLite3::ConstraintException: FOREIGN KEY constraint failed: DELETE FROM "portfolios" WHERE "portfolios"."id" = ?
error. All the associations look right. I used this same pattern for my tags on other models and it worked with no issues. Any help would be great.
You are deleting from portfolios table, but table portfolio_skills has a column referencing it as foreign key. Hence the error.
Trying to delete a parent without checking and deleting its associated children can lead to data inconsistency. This exception is in place to prevent that.
Rails dependent destroy will take care of removing associated children rows while removing a parent.
Try using a dependent destroy:-
class Portfolio < ApplicationRecord
has_many :portfolio_skills, :dependent => :destroy
...
end

Could not find table 'tags_travels' rails

I have a problem, I want to create an hashtags system, but when I run my code, and when I want to create a travel that contain hashtags I have this error :
ActiveRecord::StatementInvalid in TravelsController#create
Could not find table 'tags_travels'
Here is my travel.rb
class Travel < ApplicationRecord
has_many :posts
belongs_to :user
has_and_belongs_to_many :tags
#after / before create
after_create do
travel = Travel.find_by(id: self.id)
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
before_update do
travel = Travel.find_by(id: self.id)
travel.tags.clear
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
end
my tag.rb
class Tag < ApplicationRecord
has_and_belongs_to_many :travels
end
the schema.rb file (just table concerned) :
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "topics", force: :cascade do |t|
t.string "title"
t.string "text"
t.string "end_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
create_table "travels", force: :cascade do |t|
t.string "name"
t.string "trip_type"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "hashtags"
end
create_table "travels_tags", id: false, force: :cascade do |t|
t.integer "travel_id"
t.integer "tag_id"
t.index ["tag_id"], name: "index_travels_tags_on_tag_id"
t.index
["travel_id"], name: "index_travels_tags_on_travel_id"
end
Someone has a solution ? Thank !
Rails looks for join tables in a specific syntax. Its trying to find tags_travles but uouve created it with travels_tags.
Change your model associations to specify the join table.
has_and_belongs_to_many :travels, :join_table => :travels_tags
And
has_and_belongs_to_many :tags, :join_table => :travels_tags
Heres some info from the docs to help explain the defsult behaviour for join table naming.
"By default, the name of the join table comes from the union of the first two arguments provided to create_join_table, in alphabetical order."
http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-join-table

Can't write unknown attribute using rails_admin

Im' using rails_admin to save a project that has a category within. I didn't define project_id and category_id because I thought they should be created by rails. The problem I got were using the method def category_id=(id) defined in project model (see below). The error is:
can't write unknown attribute `project_id`
My models are:
Category
class Category < ActiveRecord::Base
belongs_to :project, :inverse_of => :category
end
Project
class Project < ActiveRecord::Base
has_one :category, :dependent => :destroy, :inverse_of => :project
def category_id
self.category.try :id
end
def category_id=(id)
self.category = Category.find_by_id(id)
end
end
My schema:
create_table "categories", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "projects", force: :cascade do |t|
t.string "title"
t.text "text"
t.string "url"
t.string "key_feature"
t.string "image_1"
t.string "image_2"
t.string "image_3"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
How do you connect Projects to Categories?
Base on your schema Projects table has no category_id.
Neither you Category table has project_id
I would add category_id to Projects table.
rails g migration add_category_id_to_projects category_id:integer
rake db:migrate
The solution at the end was to manually add the project_id to categories table.
rails g migration add_project_id_to_categories project_id:integer
Thanks #Misha for you suggestion.

How do you add data to a model's has_many relationship programatically in Rails?

In this app I have three models - Players, Teams and Rounds.
class Player < ActiveRecord::Base
has_and_belongs_to_many :teams
end
class Team < ActiveRecord::Base
has_and_belongs_to_many :players
belongs_to :round
end
class Round < ActiveRecord::Base
has_many :teams
end
In each round, a different amount of teams will be generated based on the number of players that are sent in (Players are to be persistent, but in each round you can select the ones that will actually play this time around). Once the teams are created, they are populated with the list of players for this round.
In my RoundsController i've setup a method which gets called in the create action for a new Round.
def createTeams
totalPlayers = #players.length
noOfTeams = totalPlayers/5
while (noOfTeams > 0) do
team = Team.new
team.round = #round
team.save
noOfTeams -= 1
end
i = totalPlayers - 1
while (i >= 0) do
#round.teams.each do |team|
player = #players.at(i)
player.team = team
player.save
i -= 1
end
end
At the moment I can't actually set the team's round to the current round, I get a 'can't write unknown attribute round_id' error. Am I going about this the right way? Have I setup my relationships correctly? I thought I would be able to do something like #round.teams.build(team) or #round.teams.add(team)... Any help appreciated, sorry if this is a duplicate but I've been searching around for a while without any luck.
Here's the Schema:
ActiveRecord::Schema.define(version: 20150310124456) do
create_table "players", force: :cascade do |t|
t.string "first_name"
t.string "surname"
t.string "email"
t.string "phone"
t.integer "goals"
t.integer "clean_sheets"
t.integer "wins"
t.integer "draws"
t.integer "losses"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "players_teams", id: false, force: :cascade do |t|
t.integer "player_id"
t.integer "team_id"
end
add_index "players_teams", ["player_id"], name: "index_players_teams_on_player_id"
add_index "players_teams", ["team_id"], name: "index_players_teams_on_team_id"
create_table "rounds", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "teams", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
You are missing a round_id from Team.
In a migration you can simply use
add_column :teams, :round_id, :integer
to fix this. An id like this is required if you have a belongs_to in a model.
And to add to a round
#round.teams << team

Resources