1

I have two content types: Ingredient and Recipe Sheets.

Both Ingredient and Recipe Sheet have a term refence field called Allergens.

Ingredient has the Allergens term reference field filled in. IE: Milk, Gluten.

While in Recipe Sheets Allergens is empty.

Ingredient has an Entity Reference to Recipe Sheets.

Now, I want when Ingredient content type is viewed, to automtiacally copy all the terms from allergens and put them into the Allergens of the Recipe Sheet that is entity referenced (the entity reference field can only have 1 value).

In my rule, when Ingredient is viewed, I use Action of loop then item list to get all the Allergen field terms from A (Ingredient). Then another action to run my component and I pass that list to my component.

Here is my component ("B" refers to "Recipe Sheet"):

enter image description here

When I do this action, for Allergens, only the last tax term gets checked in B.

How do I get it, so it checks all the terms from the list and not just the last one?


Sample Rules Export:

{ "rules_testing" : {
    "LABEL" : "Testing",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "ON" : { "node_view" : [] },
    "IF" : [
      { "node_is_of_type" : {
          "node" : [ "node" ],
          "type" : { "value" : { "ingredients" : "ingredients" } }
        }
      }
    ],
    "DO" : [
      { "LOOP" : {
          "USING" : { "list" : [ "node:field-allergens" ] },
          "ITEM" : { "list_item" : "Current list item" },
          "DO" : [
            { "entity_fetch" : {
                "USING" : { "type" : "taxonomy_term", "id" : [ "list-item:tid" ] },
                "PROVIDE" : { "entity_fetched" : { "entity_fetched" : "Fetched entity" } }
              }
            },
            { "component_rules_lalala" : {
                "node_referenced" : [ "node:field-reference" ],
                "nids_of_terms_from_allergens" : [ "entity-fetched:parents-all" ]
              }
            }
          ]
        }
      }
    ]
  }
}

Sample Component Export:

{ "rules_lalala" : {
    "LABEL" : "lalala",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "USES VARIABLES" : {
      "node_referenced" : { "label" : "Node(s) from Entity Reference", "type" : "node" },
      "nids_of_terms_from_allergens" : {
        "label" : "NIDS of Allergens from Ingredients",
        "type" : "list\u003Ctaxonomy_term\u003E"
      }
    },
    "IF" : [
      { "node_is_of_type" : {
          "node" : [ "node-referenced" ],
          "type" : { "value" : { "recipe_sheets" : "recipe_sheets" } }
        }
      }
    ],
    "DO" : [
      { "data_set" : {
          "data" : [ "node-referenced:field-allergens" ],
          "value" : [ "nids-of-terms-from-allergens" ]
        }
      }
    ]
  }
}
4
  • Thank you for the accept! Maybe it's time now for a followup question .... what should happen to the Allergens of the Recipe Sheet after an Ingredient is deleted? Ie should the allergens terms that were copied before be removed again in the Recipe sheet? If so can you think of a minor tweak of the rule/rules component to handle that case? Another question: what if terms are added or removed in an Ingredient? Nov 22, 2016 at 6:43
  • @Pierre.Vriens excellent questions. In my actual project, the Recipe Sheets reference the Ingredients. So my when Rule Recipe Sheets is viewed → component of Ingredients (grab the allergens) → component Recipe Sheets (set the allergens). So all I did was clear all the allergens in the Rule by removing items from list. Then the components will re-add them if they exist.
    – No Sssweat
    Nov 22, 2016 at 9:02
  • @Pierre.Vriens I was also tasked to update when Ingredient allergens is updated. I was going to use Corresponding Entity References Module but who needs this? with my new found knowledge, I can do the same using rules.
    – No Sssweat
    Nov 22, 2016 at 9:05
  • PS: of course the actual rule will be triggered when save/delete, just using viewed as trigger for testing purposes.
    – No Sssweat
    Nov 22, 2016 at 9:07

1 Answer 1

1

Part 1: Understanding the problem

Your action Set a data value can only set 1 value, which explains what you currently experience, i.e the last one.

Try to replace that action with an action "Add an item to a list". When doing so, you probably also want to set "ENFORCE UNIQUENESS" to true, so that you "only add the item to the list if it is not yet contained". Even though for your case it may not make a difference, IMO that is a kind of safety-belt when using this action.

However, you also have to add a prior action like "Fetch entity by ID", before this "Add an item to a list".

For more details, have a look at the tutorial "Lists and loops", starting from around 9:00.

Part 2: Fixing the problem

Below are more detailed instructions, where appropriate with references to the equivalent that is shown in that video. And a corrected Rule and Rules Component (in Rules export format).

Step 1: Simplify the Rule

In the Rule that calls your Rules Component, apply these changes:

  • Delete all Rules Actions you had added (sorry ...).
  • Only add 1 action, which is to invoke the Rules Component with 2 appropriate parameters, i.e.:
    • for Node(s) from Entity Reference use node:field-reference as its data selector
    • for List of Allergens from Ingredients use node:field-allergens as its data selector.

Here is an export of what I recommend as your (corrected) Rule:

{ "rules_copy_all_terms_to_another_node" : {
    "LABEL" : "Copy all terms to another node",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "ON" : { "node_view" : [] },
    "IF" : [
      { "node_is_of_type" : {
          "node" : [ "node" ],
          "type" : { "value" : { "ingredients" : "ingredients" } }
        }
      }
    ],
    "DO" : [
      { "component_rules_add_a_term_to_a_node" : {
          "node_referenced" : [ "node:field-reference" ],
          "list_of_allergens_terms" : [ "node:field-allergens" ]
        }
      }
    ]
  }
}

Step 2: Rework the Rules Component

In your Rules Component, apply these changes:

  • Remove the action to "Set a data value" (we'll use Rules Action "Add an item to a list" instead, as detailed below).
  • The 2 parms you passed to the Rules Components seem OK (I just slightly renamed them to improve readability).
  • Add a loop, to iterate over each term contained in the list of terms (which is passed as a parameter), and add the extra Action for each item in this loop, like so:
    • Add an action Fetch entity by ID, whereas you want to fetch (= load) a taxonomy term, similar to what is shown in the video around 10:40. And the ID of what you want to fetch is the 2nd parm of your Rules Component, followed by ":tid", similar to what is shown in the video around 10:50, though your Rules Component should use "data selection" to select your 2nd parm (the video just uses a data identifier of "1"). Make sure to remember what you use as variable name here similar to what is shown in the video around 11:20, let's assume you name it "(allergens_term_fetched".
    • Add an action to Add an item to a list, similar to what is shown in the video around 11:40. The data list to which an item is to be added in your case is node-referenced:field-allergens (instead of node:field-tags as shown in the video). While doing so, the next thing is similar to what is shown in the video around 12:00: the "item to add" should be "(allergens-term-fetched" (if you used that name I suggested). You probably also want to check the "enforce uniqueness" (see video around 12:40, though the video does not check it), and for "insert position" I'd use "append the item to the end" (see video around 12:55).
  • Note: the Rules Condition in your Rules Component is fine (and also similar to what is shown in the video), no changes needed to that.

Here is an export of what I recommend as your (corrected) Rules Component:

{ "rules_add_a_term_to_a_node" : {
    "LABEL" : "Add a term to a node",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "USES VARIABLES" : {
      "node_referenced" : { "label" : "Node(s) from Entity Reference", "type" : "node" },
      "list_of_allergens_terms" : {
        "label" : "List of Allergens from Ingredients",
        "type" : "list\u003Ctaxonomy_term\u003E"
      }
    },
    "IF" : [
      { "node_is_of_type" : {
          "node" : [ "node-referenced" ],
          "type" : { "value" : { "recipe_sheets" : "recipe_sheets" } }
        }
      }
    ],
    "DO" : [
      { "LOOP" : {
          "USING" : { "list" : [ "list-of-allergens-terms" ] },
          "ITEM" : { "next_allergens_term" : "Next Allergens term" },
          "DO" : [
            { "entity_fetch" : {
                "USING" : { "type" : "taxonomy_term", "id" : [ "next-allergens-term:tid" ] },
                "PROVIDE" : { "entity_fetched" : { "allergens_term_fetched" : "Fetched Allergens term" } }
              }
            },
            { "list_add" : {
                "list" : [ "node-referenced:field-allergens" ],
                "item" : [ "allergens-term-fetched" ],
                "unique" : "1"
              }
            }
          ]
        }
      }
    ]
  }
}

Step 3: Time for QA-testing

Only believe what you've seen with your own eyes ... So use the Rules UI to import my corrected Rule and Rules Component. If you didn't do so yet, make sure you have a content type with the same machine name ingredients (doesn't matter what the content type of the entity referenced node is). And also make sure both content types have a term reference with machine name allergens. If the import fails, it must be because those machine names don't match, or the fields are missing (so fix that and retry the import).

After the import completed, and you have at least 1 node of each type (with an entity reference), it's Party Time ... Make sure your taxonomy terms include terms like salt, pepper, strawberries, bananas, whatever.

FYI: in my experimental setup, the combination of the above Rule and Rules Component seemed to work as requested in the question here ... one of my terms for testing was ... Champagne.

Voilà ... No custom code, sweat, no?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.