mattbeedle / capsule_crm

Ruby CapsuleCRM API consumer
MIT License
26 stars 16 forks source link

Custom Field Creation. #64

Closed jonathansimmons closed 10 years ago

jonathansimmons commented 10 years ago

I'm having trouble working out how to add a custom field on person and organisation.

This only way I've found that works is to add them after the person is created:

person = CapsuleCRM::Person.create(first_name: "Jonathan", last_name: "Simmons")
person.custom_fields << CapsuleCRM::CustomField.new(label: 'field_name', text: 'field_value')
person.save

The above method does not work when trying to add custom_fields to an organization though...

My preferred method would be to add the custom field inline with the create like so:

 person = CapsuleCRM::Person.create(
    first_name: "Jonathan", 
    last_name: "Simmons", 
    custom_fields: CapsuleCRM::CustomField.new(
         label: 'field_name', 
         text: 'field_value'
    )
  )

This returns the following error:

NoMethodError: undefined method `map' for #<CapsuleCRM::CustomField:0x007fdea4188820>
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/serializer.rb:20:in `serialize_collection'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/associations/has_many_proxy.rb:44:in `to_capsule_json'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/associations/has_many_proxy.rb:48:in `save'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/associations/has_many.rb:47:in `block in has_many'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:405:in `_run__2604789604786209564__save__2761873270767723794__callbacks'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:405:in `__run_callback'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:385:in `_run_save_callbacks'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:81:in `run_callbacks'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/persistence/persistable.rb:25:in `save'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/persistence/persistable.rb:15:in `tap'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/capsule_crm-1.5.2/lib/capsule_crm/persistence/persistable.rb:15:in `create'
from (irb):12
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.17/lib/rails/commands/console.rb:47:in `start'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.17/lib/rails/commands/console.rb:8:in `start'
from /Users/jonathan/.rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.17/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'1.9.3p392 :013 > 

After reviewing #40 I tried the build method shown:

person.custom_fields.build(label: 'field_name', text: 'field_value')
person.save!

But that does not work on v 1.5.2 either.

If I can get some clarity on this I can make a pull request to update the readme with more examples.

To recap: What is the suggested method for adding a custom field? more than one at a time? And are they meant to function with organizations as they don't appear to now?

jonathansimmons commented 10 years ago

@mattbeedle Could you weigh in on this so I know which direction I should take?

mattbeedle commented 10 years ago

Hey @jonathansimmons. I just got around to trying this out. Sorry about the delay. All of these examples worked fine in my test account.

Example 1

It's my guess that in your first example (the one that works for people but not organizations), you configured the custom field in capsulecrm to only be just for people.

capsulegemtest_crm

I logged into my test account and configured a custom field with label "Just Testing" for both people and organizations. Here is the result:

1__ruby

Example 2

In the second example you are passing a CapsuleCRM::CustomField into a method that expects an Array. To make it work you would need to use an Array like so:

person = CapsuleCRM::Person.create(
  first_name: "Jonathan", 
  last_name: "Simmons", 
  custom_fields: [
    CapsuleCRM::CustomField.new(
       label: 'field_name', 
       text: 'field_value'
    ]
  )
)

Ideally the custom_fields method should be smart enough to work when it is passed an object too. I've created a ticket for this here #66.

Example 3

Finally, in the third example, are you actually passing in the string: "field_name" to the label? If you are this would lead capsulecrm.com to respond with a 404 error because there is no custom field definition for that label. You need to define the custom fields with the labels you need in the capsulecrm.com UI. So to make that example work, you would need to do this:

capsulegemtest_crm

mattbeedle commented 10 years ago

Ok @jonathansimmons, you can now pass singular objects to a has many, so this should now work (as long as the custom field definition exists in your capsulecrm.com configuration):

person = CapsuleCRM::Person.create(
    first_name: "Jonathan", 
    last_name: "Simmons", 
    custom_fields: CapsuleCRM::CustomField.new(
         label: 'field_name', 
         text: 'field_value'
    )
  )

I'll try to generate some documentation soon so that you can easily check what arguments you can send to public methods. If in doubt though you can always check the source. Most of the public methods are documented. https://github.com/mattbeedle/capsule_crm/blob/master/lib/capsule_crm/associations/has_many_association.rb#L35

Also, when an error is raised it now displays the message that the capsulecrm.com API returned. This should make it a bit easier to debug issues like the one here where a custom field definition does not exist for the custom field that you are trying to create.

1__ruby

jonathansimmons commented 10 years ago

@mattbeedle I'm just getting around to finally using custom fields but I'm having trouble once again.

tl;dr saving custom fields appears to only work the first time. The lack of accurate errors is hindering debug.

Scenario: A custom rake task to update each of our records custom fields nightly.

relevant snippet from this task:

capsule_org = CapsuleCRM::Organization.find(12345)
capsule_org.custom_fields << CapsuleCRM::CustomField.new(label: 'some_text_field', text: 'some text')
capsule_org.custom_fields << CapsuleCRM::CustomField.new(label: 'some_boolean_field ', boolean: 'true' )
capsule_org.custom_fields << CapsuleCRM::CustomField.new(label: 'some_date_field ', date: Date.today )
capsule_org.save

The above will save the custom fields the first time when they are blank in capsule. However If I run this code again I begin getting an error response of: #<CapsuleCRM::Errors::BadRequest: capsulecrm.com returned an empty response> Which appears capsule is being unhelpful....

Looking into it further though I tested setting and updating these fields using a REST client app Rested.app for mac. Both setting and updating the custom field values worked fine.

that request was as follows:

URL: PUT /api/party/[party_id]/customfields
Request Headers and body:
  Accept: */*
  Accept-Encoding: gzip, deflate
  Content-Type: application/json
  Accept-Language: en-us

  {
    "customFields": {
      "customField": [
        {
           "label": "text_field",
          "text": "some text"
        },
        {
          "label": "date_field",
          "date": "2011-03-13T00:00:00Z"
        },
        {
          "label": "boolean_field",
          "boolean": "true"
        }
     ]
    }
  }
Response Headers
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <customFields size="3">
      <customField>
          <id>66378839</id>
          <label>text_field</label>
          <text>some text</text>
      </customField>
      <customField>
          <id>66378841</id>
           <label>date_field</label>
          <date>2011-03-13T00:00:00Z</date>
      </customField>
      <customField>
           <id>66378872</id>
           <label>boolean_field</label>
           <boolean>true</boolean>
       </customField>
</customFields>

The ultimate goal here is to be able to set any type of custom field at any time regardless of whether or not it already has a value. The fact that my example works the first time but not subsequent times confuses me but the errors returned don't help the debug process. I don't think the value existing should prevent me from setting it which was proved true by the raw API call using rested.app.

So something about the capsule gem is preventing the save the second time around. I just can't tell what. Your thoughts and help on this are greatly appreciated.

As for debug, to me it looks like there is still an inconsistency in how the capsule_crm gem is capturing errors almost as if it's now returning a nil response from capsule when it shouldn't. I'm unsure of how to fix it, despite having poked around trying.

mattbeedle commented 10 years ago

hmmm, this seems like a tricky one. The request being sent from the gem seem seems to be identical to the one you are sending manually. I will have to dig into this one. I also find it a bit confusing that you are sending JSON and capsule is replying with XML. Also, according to the capsule developer docs the response body should be blank.

mattbeedle commented 10 years ago

You can try using the fix-errors branch to see more descriptive error messages for now. Not merged yet as tests are incomplete.

jonathansimmons commented 10 years ago

Ok so using the fix-errors branch not error is now:

#<CapsuleCRM::Errors::BadRequest: duplicate use of custom field>

Let me know if you think this is due to the gem or if I need to reach out to capsule.

mattbeedle commented 10 years ago

I'm not sure yet. I'll continue to debug and speak with capsule if needed. I'll keep you updated.

mattbeedle commented 10 years ago

Are you sure that you are not adding custom fields with the same label twice to an object in capsule? Custom field labels are unique. I was only able to replicate the issue by adding the same custom field two times to an organization.

I have two custom fields set up in my capsulecrm test account:

capsulegemtest_crm

# First create an organization
org = CapsuleCRM::Organization.new name: 'GoHiring GmbH'
 #=> #<CapsuleCRM::Organization:70182601008360 id: , name: GoHiring GmbH, about: >

# Now add the first custom field to it
org.custom_fields.build label: 'Just Testing', text: 'some filler text'
# => #<CapsuleCRM::CustomField:70182597969720 id: , label: Just Testing, date: , tag: , boolean: , text: some filler text, party_id: , opportunity_id: , case_id: >

# Save the org, everything works fine
org.save
# => #<CapsuleCRM::Organization:70182601008360 id: 67161231, name: GoHiring GmbH, about: >

# Add another custom field
org.custom_fields.build label: 'testing 2', text: 'some more filler text'
#=> #<CapsuleCRM::CustomField:70182628787140 id: , label: testing 2, date: , tag: , boolean: , text: some more filler text, party_id: 67161231, opportunity_id: , case_id: >

# Save the org, everything works fine again
org.save
#=> #<CapsuleCRM::Organization:70182601008360 id: 67161231, name: GoHiring GmbH, about: >

# Now try to add a custom field with a label that I already used
org.custom_fields.build label: 'Just Testing', text: 'even more filler text'
#=> #<CapsuleCRM::CustomField:70182598104840 id: , label: Just Testing, date: , tag: , boolean: , text: even more filler text, party_id: 67161231, opportunity_id: , case_id: >

# Save the org, raises a BadRequest error
org.save
# => CapsuleCRM::Errors::BadRequest: duplicate use of custom field

BTW, if you use the latest master you will now get cleaner object inspection making it a bit easier to see what is going on in the console. There is also a perform_logging option in the configuration so you can see what the gem is sending to capsule.

jonathansimmons commented 10 years ago

We are not setting the same custom field at the same time as you illustrated in your example, but we are trying to keep the custom field updated on a nightly bases.

So we intend to run a rake task each night that will set or update the custom field values for each organisation. After some testing on the master branch with perform_logging enabled it appears my direct issue is the syntax I'm are using. << or build are just adding the a new instance of the custom field to the companies existing custom field array. Hence the CapsuleCRM::Errors::BadRequest: duplicate use of custom field. My question now is how, utilizing this gem, can we update a custom field without first having to check to see if it's set.

Side notes: Errors do seem to be working as expected in master. The perform_logging tip was quite helpful. Thanks again.

mattbeedle commented 10 years ago

Ok, got it. Right now there is no way to do that. I'm also not really sure if that functionality should be added to the gem either. I would prefer to raise and error in that case or perhaps invalidate the model. I'll have a think about that though. Also open to suggestions for how that API could look.

mattbeedle commented 10 years ago

I guess for now though you should just implement something like this

custom_field = object.custom_fields.select { |c| c.label == 'something'  }.first || object.custom_field.build
# make changes to the custom field
object.save
mattbeedle commented 10 years ago

So this issue can be closed now?

jonathansimmons commented 10 years ago

Having to handle custom fields like a true object feels odd to me because they are essentially attributes but I can respect the lack of desire to build this into the gem.

We'll just work around this internally. If I can think of a better solutions I'll make a branch when I have time.