Programmatically generated Spree Taxons not showing tree in Admin - ruby-on-rails

I am trying to generate a Spree Commerce taxonomy programmatically within a Ruby script (a la seeds.rb). In the customer-facing product pages the Taxons appear, but they do not work from the Admin pages.
The "tree" view of the Taxonomy shows the root node, but no children
On the product edit page, I cannot add any of my Taxons
Here's an example:
taxonomy_stones = Spree::Taxonomy.where(:name => 'Gemstone Type').first_or_create
tax_stones = Spree::Taxon.where(name: "Gemstone", parent: nil, taxonomy: taxonomy_stones).first_or_create
tax_diamond = Spree::Taxon.where(name: "Diamond", parent: tax_stones, taxonomy: taxonomy_stones).first_or_create
tax_fancy_yellow = Spree::Taxon.where(name: "Fancy Yellow Diamond", parent: tax_diamond, taxonomy: taxonomy_stones).first_or_create
tax_fancy_pink = Spree::Taxon.where(name: "Fancy Pink Diamond", parent: tax_diamond, taxonomy: taxonomy_stones).first_or_create
When I run this, entries appear in the database for my Taxonomy and Taxons. I am able to programmatically associate Products to the Taxons:
product_BL212.taxons << tax_diamond
I'm guessing that my Taxon-creation code is incomplete or incorrect in some way, but I am not sure how. Can anyone who is more familiar with Spree's internals provide an example of doing this correctly?
Further Observations
I used the Admin UI to create sample Taxonomies and have compared the database entries to my generated ones. The name and permalink fields in spree_taxons are blank for my generated Taxons, but not the Spree-created ones. When I manually populated some of the values for the root node and two sample children, the taxonomy/taxons still don't work correctly in Admin.
Is it important to have these values populated in spree_taxons when spree_taxons_translations has the needed information?
If so, how do I get Spree to populate the values for these fields correctly?

Calling Spree::Taxon.rebuild! after adding the Taxons resolves the issue.

I had a similar issue where I had the code
Spree::Taxonomy.find_or_create_by(name:'Brands')
Spree::Taxon.find_or_initialize_by(name:'brand_name').update(taxonomy: Spree::Taxonomy.find_by(name:'Brands'))
Running Spree::Taxon.rebuild! did not solve the issue. I found out that creating a Taxonomy also creates a Taxon with it and I had to use the ID for the associated taxon in the parent column for the new taxon I was creating.
So
Spree::Taxon.find_or_initialize_by(name:'brand_name').update(taxonomy: Spree::Taxonomy.find_by(name:'Brands'))
had to be changed to
Spree::Taxon.find_or_initialize_by(name:'brand_name').update(taxonomy: Spree::Taxonomy.find_by(name:'Brands'), parent: Spree::Taxon.find_by(name:'Brands'))

The Taxon.parent attribute expects a root object.
For example:
t = Spree::Taxonomy.create(name: "Season")
tt = Spree::Taxon.create(name: "Winter", taxonomy: t, parent: t.root)

Related

rails can you reference a model within a model?

I seem to have run into a problem with trying to use a model in another model in Rails.
I am pulling a list of users from Active Directory with LDAP in a dropdown. I want to parse the cn that I get from Ldap into a firstname and lastname.
The problem I am running into is that I need to find a record in the users model. The parsing is being done in observations.rb.
Observation.rb:
def parse_employee
#emp_name = '' #initialize
self.employee_raw = self.employee_raw[2...-2] # get rid of the quotes and brackets
#emp_name = self.employee_raw.split(' ') # split first/last names
#emp_first_name = #emp_name[0] #Grab the first name
#emp_last_name = #emp_name[1] # grab the surname
#user = User.where("last_name like ?", #emp_last_name)
self.employee_id = #user.id
end
I've played with this quite a bit and it appears that I can't reference other models from within a model.
To sum up, what I am trying to do is
1. Have the user select the appropriate person from a dropdown that is pulled via LDAP from active directory.
2. Use the first and last names to find the appropriate user in my user table (Right now I'm just trying to get it to work with the last name as that is unique enough)
3. When I find the correct user in the user table, enter that id in the employee_id field in my observations table.

Rails checking if an object is also assigned to another

in my Rails application I've got a n:m relation between movies and tags. (has_and_belongs_to_many)
So each tag can be assign to several movies.
Now when I add new tags to a movie I want to check If this Tag is already assigned to this movie.
What is the esiest way in rails to check if there is a relation ship between the tag and the movie?
I fetch the tag with:
#tagfound = Tag.where("tagname = ?", data[:tagname])
The List with all Tags from the movie can be fetched with this:
#vid.tags
Thanks for your help
You may not need to check. You can simply do this
movie.tags = [array, of, tags]
movie.save # note, you don't need to save. The line above saves.
or
movie.tag_ids = [1,2,3,4]
movie.save # note, you don't need to save. The line above saves.
and that will take care of it setting new tags and removing the ones that are no longer connected. Good for checkbox UI or a tokenizer.
To answer your question, to find if a movie has a tag, you can do this
tag.in?(movie.tags)
And this is the way to add a single
movie.tags << tag unless tag.in?(movie.tags)
[EDIT]
If you do this
movie.update_attributes(movie_params)
and one of the params is the tag_ids, the movie will only save the new tags if it is valid (no other errors).
I believe there are 2 ways you can do this.
Check if #tagfound is included in #vid.tags
#vid.tags.include? #tagfound
Add the tag & call uniq after.
#vid.tags << #tagfound
#vid.tags.uniq!

Select all records that are not associated with other

I have two tables pages and menu_items, pages HAS MANY menu_items and menu_items belongs_to pages. In Rail 4 how can I select only those pages that are not linked with menu_items?
Thanks in advance!
Each of the following should work:
Page.includes(:menu_items).where( menu_items: { page_id: nil} )
or
Page.find(:all, conditions: { :menu_items.count: 0 } )
or
Page.where('id NOT IN (SELECT DISTINCT(page_id) FROM menu_items)')
Perhaps Page.where is what you're looking for. Effectively the where method calls a search through the Page database for all objects of the specified type. By calling it with the parameter of the menu's id equal to nil, you are searching for all pages where there is no menu id.
Ideally you would like to call Page.where(page.menu_items.empty?), however, of course, this isn't allowed.
Looking around this question is more or less exactly the same as yours. They solve it with:
Page.includes(:menu_items).where( :menu_items => {:page_id=>nil} )

Ordering with awesome_nested_set

As I have find out awesome_nested_set is the most popular Rails gem for making categories tree. Unfortunately, it hasn't categories ordering function or it isn't docummented.
Maybe anyone knows how to change these categories order?
Menu
- about
- first page
- second page
- contacts
I don't know how to to add some new categories in the middle of the tree.
Say that the node called first page is an instance of the model Page and has the ID 3. You can do the following:
first_page = Page.find(3)
new_page = Page.create(:name => 'new page')
new_page.move_to first_page, :right
This will create a new page called new page and put it between first page and second page.
EDIT: after looking at the code, it appears that there is now also a method move_to_right_of, which might be more convenient.

How to best copy/clone an entire nested set from a root element down with new tree

I am using "acts_as_nested_set" in my rails app. (extended with awesome nested set plugin). I was trying to logic out the best way to write a function/method to clone an element and its entire nested set so that each element gets a clone but the relationship structure mimicks the original, just with the new elements.
With nested sets you get parent_id, lft, and rgt positional columns... instead of just position_id.
Should I start at the bottom (nodes with no children) of each set and clone up through the parents all the way to a new root?
This seems like either something that has been done or that there would be a method for doing this already for nested sets but I can't see to find anything to guide me.
Thanks
I did something like this with acts-as-tree. I iterated over the collective set and cloned each item. I saved the source item and the cloned item in a hash where the source was the key and the clone the target. I then used the hash along with the parent references to resolve and remap the relations.
Here's a snippet to help convey the gist.
The clone method simply instantiates a new copy without an id. The descendants method returns a full list of descendants not just immediate ones.
def clone_branch()
h = {self => self.clone} #we start at the root
ordered = self.descendants #preserved order with acts_as_sortable
#clone subitems
ordered.each do |item|
h[item] = item.clone
end
#resolve relations
ordered.each do |item|
cloned = h[item]
item_parent = h[item.parent]
item_parent.children << cloned if item_parent
end
h[self]
end

Resources