CakePHP 4 -> how to save join record - join

I'm working on a CakePHP 4 application and I've set up a join table between Categories and Products called CategoriesProducts.
When I'm creating a new Product with a property called categories_products which contains an array like:
[
[
'category_id' => `x`
]
]
What's supposed to be saved into the join table is the category_id with the newly generated product_id.
The data isn't saved to the join table.
In the saveMany function I pass the:
[
'associated' => [
'Categories'
]
]
When I try to add associated => CategoriesProducts I get an error that the relationship is not defined.
Can someone explain to me how I can fill the join table? I've setup the database and baked the models with the CakePHP helper.
Thanks in advance!

With the default association saving process you do not need to add data for join tables directly, instead you use the target association property and provide the primary keys of the records that you want to link.
So in your case that would probably be categories, eg your data for patching/creating an entity would be structured like this, where id is the primary key of the existing category that you want to associate to your new product:
[
// ...
'categories' => [
[
'id' => 123,
],
],
]
The ORM will then create the proper join table record automatically.
See also
Cookbook > Database Access & ORM > Saving Data > Converting BelongsToMany Data

Related

How can I reference an object with a dropdown input in Rails?

I have models Order and Vendor. Order has vendor, description, items, cost fields, and Vendor has name, email, phone.
When a user creates a new Order, I would like them to select the Vendor's name from a dropdown input, which references the whole relevant Vendor objects in the Order's vendor field.
As per my understanding. you have following associations
Vendor has_many Orders
Order belongs_to Vendor [In order we need to store vendor_id]
So in that case in your new order form you need to add
<%= f.select(:Vendor_id, Vendor.all.collect { |v| [ v.name, v.id ] }, {}, { "data-placeholder": "Select Vendor" }) %>
This will give you selected vender_id in parameters. Hope this will work for you.
Thanks!

Ruby - ActiveAdmin CSV custom import

Currently I have an ActiveAdmin page which gets data from a CSV file to populate a database table (users). This table has one unique identifier which is not the ID used in relationships (a user-friendly code for users to view).
The page does this via "active_admin_import"
Now, I want the same thing to populate another table (user_paths), the problem is, this table uses foreign keys from the "users" table, so I want the CSV file to contain this unique identifier from "users" table.
Is there any solution for this?
sorry for late response.
Just lately I added new example to gem wiki that is very similar to your problem.
It can be solved with custom before_batch_import hook using master branch
Next example demonstrates how to resolve author_id value from author name and change csv values dynamically before performing insert query.
ActiveAdmin.register Post do
active_admin_import validate: true,
headers_rewrites: { :'Author name' => :author_id },
before_batch_import: ->(importer) {
authors_names = importer.values_at(:author_id)
# replacing author name with author id
authors = Author.where(name: authors_names).pluck(:name, :id)
options = Hash[*authors.flatten] # #{"Jane" => 2, "John" => 1}
importer.batch_replace(:author_id, options) #replacing "Jane" with 1, etc
}
end

Generating array of hashes from RoR query output?

Rails novice here. Say I have two tables, Owners (owner_id, name) and Cats (cat_id, cname). They're associated via a one-to-many relationship where an owner can own many cats but a cat can only have one owner. Given an input of owner_id, I want to retrieve the cat name and id for each cat owned by that Owner, and store it as an array of hashes (i.e. [{:cat_id => 1, cname => "cat1"}, {:cat_id => 2, cname = "cat2"}].
So far I have something like output = [Owner.find(owner_id).join(:Cats)] but I'm not sure how to complete the statement. Thank you so much.
Owner.find(owner_id).cats will give you what you want.
Try this:
Cat.all(:conditions => ['owner_id = ?', owner_id])
Or:
Owner.find(owner_id).cats
That one assumes you have has_many :cats in your Owner model. If you need a list of hashes instead of active record objects you can use .collect to transform your set.

IF/CASE statement OR MySQL OR array for get category name

On my site I got entries which have category. Site have only 5 categories, so I have dilemma:
Make relationship between category table and entries (category_id) table
OR
Make method which return category name via IF/CASE statement? Like:
case #entry.category.id
when 1
"Games"
when 2
"Movies"
when 3
"Fun"
[...]
end
(I remind that I must get 10 category name per page)
OR
Use array:
cat[1] = "Games"
cat[2] = "Movies"
cat[3] = "Fun"
[...]
<%= cat[#entry.category.id] %>
I think this relation definitely belongs into the database. (adding a category table)
it is the most sane and most scalable option.
It is also the cleanest, because you break the seperation of data, display and logic (MVC: model, view, controller) when hardcoding the categories in your application.
you can easily select the item AND its category with a single query:
SELECT item.*, category.name
FROM item
LEFT JOIN category ON category.id = item.category_id
WHERE some=condition
there are similar queries for INSERTs and UPDATEs (at least in MySQL), so you never need a second query.
If the only thing you care about category is "name", then you should just store the category_name in the entries table.
OR
Make a constant CATEGORY_NAME and wrapper method to get the name with id in the entries table (without using Category table/model at all). eg.,
class Entry
CATEGORY_NAME = [ "Games", "Movies", "Fun"]
def category_name
CATEGORY_NAME[cat_id] #cat_id being just 0,1,2 .. depends how you want to store
end
...
I am sure there are many ways to achieve this anyway.
Hope it helps.

Find all objects with broken association

I have two models in my rails app with a has many and belongs to association.
Category has many items and Item belongs to category.
These models are associated in the normal way through a category_id column in the Item model.
I'm looking for a quick way of finding all elements in the database with broken associations.
i.e. find all categories that exist with no associated items and items that exist with no associated category.
For example, if I have an item with a category_id of 7, but the category with id 7 has been deleted then this would be considered broken.
For your example, to find items with category_id's for categories which don't exist any more:
Item.where('NOT EXISTS (SELECT * FROM categories where category.id = item.category_id)')
You might want to look at this as well:
A rake task to track down missing database indexes (not foreign keys though, but indexes): https://github.com/eladmeidar/rails_indexes
A very effective way is using find_by_sql to let the database do the heavy lifting:
uncategorized_items = Item.find_by_sql("select * from items where category_id IS NULL")
Another way is a named scope:
class Item < ActiveRecord::Base
scope :uncategorized, where(:category_id => nil) # rails 3
# or...
named_scope :uncategorized, :conditions => 'category_id IS NULL'
end
These are just a couple of ideas. I assume that once you've found these broken associations you plan to fix them, right? You might want to use validates_associated in both models if it's important to you that this not happen again.
You can use find_by_sql and a left outer join to find all the items in one table but not another. Here, I use a downloads table and an image_files table (I've only included the SQL):
SELECT d.*, d.image_file_id
from downloads as d
LEFT OUTER JOIN image_files as i
ON i.id = d.image_file_id
WHERE d.image_file_id IS NULL

Resources