I use Ruby on Rails 4.2.5 with the Restforce gem for Salesforce API. I create a Contact in my controller :
class CandidateFormController < ApplicationController
def index
client = Restforce.new(
:username => ENV['SALESFORCE_USERNAME'],
:password => ENV['SALESFORCE_MDP'],
:security_token => ENV['SALESFORCE_TOKEN'],
:client_id => ENV['SALESFORCE_APIKEY'],
:client_secret => ENV['SALESFORCE_SECRET'],
)
new_client = client.create('Contact', FirstName: #first_name,
LastName: #last_name,
Email: #email,
MobilePhone: #telephone,
Description: #champ_libre,
Profil_LinkedIN__c: #linkedin
)
end
end
I have a relationship between two of my tables.
Candidate is associated to Opportunity (a job offer if you prefer), and the restforce documentation doesn't explain how to create a new entry with a relation between two elements, or if it does I am not enough experimented to have understand how am I supposed to do so.
I have not enough credit to post screenshots, but if this is necesseray I can use imgur or something like that.
P.S : I already see this post on the subject, but that didn't help me at all.
Well, after another hour of research I finally find how to create relationship in salesforce.
My code looks like this now :
class CandidateFormController < ApplicationController
def index
client = Restforce.new(
:username => ENV['SALESFORCE_USERNAME'],
:password => ENV['SALESFORCE_MDP'],
:security_token => ENV['SALESFORCE_TOKEN'],
:client_id => ENV['SALESFORCE_APIKEY'],
:client_secret => ENV['SALESFORCE_SECRET'],
)
new_client = client.create('Contact', FirstName: #first_name,
LastName: #last_name,
Email: #email,
MobilePhone: #telephone,
Description: #champ_libre,
Profil_LinkedIN__c: #linkedin
)
new_candidature = client.create(
'Candidatures__c',
Candidats__c: "someId",
Offredemploi__c: new_client
)
end
end
In my case, I wanted to create a relationship between an Opportunity and a Contact (A job offer and a Candidate).
I look more into fields that already was created and filled for Opportunity and Contact in my salesforce account, and find out that there were no field that was corresponding to the relationship I was looking for.
I discover than in salesforce, there are objects that exist just for the junction between two objects, and they are called "Junction Object" (pretty obvious, but not easy to find).
You just have to create a new salesforce object with create() after the creation of your first element (a Contact for me) and create the junction object with the good type (for me it was Candidatures__c), and specify the two relationships.
In my own code I create an new Candidature__c, I specify the Id of the job offer (the Candidats__c id) and the Id of the candidate in Offredemploi__c with the Id I create some lines above.
Hope it will helps.
Related
Each user has one address.
class User
include Mongoid::Document
has_one :address
end
class Address
include Mongoid::Document
belongs_to :user
field :street_name, type:String
end
u = User.find(...)
u.address.update(street_name: 'Main St')
If we have a User without an Address, this will fail.
So, is there a good (built-in) way to do u.address.update_or_initialize_with?
Mongoid 5
I am not familiar with ruby. But I think I understand the problem. Your schema might looks like this.
user = {
_id : user1234,
address: address789
}
address = {
_id: address789,
street_name: ""
user: user1234
}
//in mongodb(javascript), you can get/update address of user this way
u = User.find({_id: user1234})
u.address //address789
db.address.update({user: u.address}, {street_name: "new_street name"})
//but since the address has not been created, the variable u does not even have property address.
u.address = undefined
Perhaps you can try to just create and attached it manually like this:
#create an address document, to get _id of this address
address = address.insert({street_name: "something"});
#link or attached it to u.address
u.update({address: address._id})
I had this problem recently. There is a built in way but it differs from active records' #find_or_initialize_by or #find_or_create_by method.
In my case, I needed to bulk insert records and update or create if not found, but I believe the same technique can be used even if you are not bulk inserting.
# returns an array of query hashes:
def update_command(users)
updates = []
users.each do |user|
updates << { 'q' => {'user_id' => user._id},
'u' => {'address' => 'address'},
'multi' => false,
'upsert' => true }
end
{ update: Address.collection_name.to_s, updates: updates, ordered: false }
end
def bulk_update(users)
client = Mongoid.default_client
command = bulk_command(users)
client.command command
client.close
end
since your not bulk updating, assuming you have a foreign key field called user_id in your Address collection. You might be able to:
Address.collection.update({ 'q' => {'user_id' => user._id},
'u' => {'address' => 'address'},
'multi' => false,
'upsert' => true }
which will match against the user_id, update the given fields when found (address in this case) or create a new one when not found.
For this to work, there is 1 last crucial step though.
You must add an index to your Address collection with a special flag.
The field you are querying on (user_id in this case)
must be indexed with a flag of either { unique: true }
or { sparse: true }. the unique flag will raise an error
if you have 2 or more nil user_id fields. The sparse option wont.
Use that if you think you may have nil values.
access your mongo db through the terminal
show dbs
use your_db_name
check if the addresses collection already has the index you are looking for
db.addresses.getIndexes()
if it already has an index on user_id, you may want to remove it
db.addresses.dropIndex( { user_id: 1} )
and create it again with the following flag:
db.addresses.createIndex( { user_id: 1}, { sparse: true } )
https://docs.mongodb.com/manual/reference/method/db.collection.update/
EDIT #1
There seems to have changes in Mongoid 5.. instead of User.collection.update you can use User.collection.update_one
https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/
The docs show you need a filter rather than a query as first argument but they seem to be the same..
Address.collection.update_one( { user_id: user_id },
'$set' => { "address": 'the_address', upsert: true} )
PS:
If you only write { "address": 'the_address' } as your update clause without including an update operator such as $set, the whole document will get overwritten rather than updating just the address field.
EDIT#2
About why you may want to index with unique or sparse
If you look at the upsert section in the link bellow, you will see:
To avoid multiple upserts, ensure that the filter fields are uniquely
indexed.
https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/
I am trying to use the composite_primary_keys gem on my application.
I made this "Enterprise" model that have "related" and "branch" attributes. Those 2 are my composite PK.
class Enterprise < ActiveRecord::Base
self.primary_key = :related, :branch
end
Using rails console, I can find my first Entreprise by using e = Enterprise.find([1,1]) without a problem.
The thing is: I can't make it work on my controller...
My show action, for example:
#enterprise = Enterprise.find(params[:id])
It gives me the error:
Couldn't find Enterprise with 'related,branch'=1,1
Parameters: {"id" => "1, 1"}
What am I doing wrong?
params[:id] is a string - you need to create an array out of it:
#enterprise = Enterprise.find(params[:id].split(',').map(&:to_i))
Composite primary key supports for string params for finding an object. The thing is you should not give space between the primary keys. So your param should be like this,
params => {"id" => "1,1"}
#enterprise = Enterprise.find(params[:id])
Try this, it should work.
When a user is created on my site I want a User.new instance to execute but I also need to make a Alias.new object too. Users have many Aliases. However, I also need to validate that there are no other Aliases with that name before saving.
From the console my code might look like this:
u = User.new(:name => "Bob")
a = Alias.new(:name => "SirBob", :user_id => u)
But that's doesn't work since u doesn't have a id until I save. So how do I validate both items for uniqueness of name before saving them?
Try this one:
u = User.new
u.aliases.build
Hope this helps...
Use
ActiveRecord::Base.transaction do
u = User.new(:name => "Bob")
a = Alias.new(:name => "SirBob", :user_id => u)
end
and add validates_uniqueness_of :name on Alias model
This will solve your problem.
I am using Mongoid and have a project and a user model.
in the Project model, I have a field
class Project
include Mongoid::Document
field :name
field :user_ids, :type => Array
end
class User
include Mongoid::Document
field :email
end
I can find all the users belonging to one project, i.e., 'find this project's users'
#project = Project.first # => 'Housework'
User.criteria.id(#project.user_ids) # => ['Bart','Lisa','Maggie']
But I am having a bit trouble finding all the projects belonging to one user, i.e, 'find this user's projects'
#user = User.first # => 'Bart'
Project.where(:user_ids => #user.id) # doesn't work
Project.where(:user_ids.includes => #user.id) # not such method
Project.where(:user_ids => [#user.id]) # doesn't make sense to compare arrays, but tried anyway and doesn't work
I know that you can have another field in the User model to store project_ids, I would gladly do that, but I am just curious, is there a method to be used in finder conditions that works similarly to #includes? in ruby?
I found a solution to this. it is the all_in finder method
example:
Fruit.all[0].colors = ['red','green','blue'] #=> apple
Fruit.all[1].colors = ['yellow','green'] #=> banana
Fruit.all[2].colors = ['red', 'yellow'] #=> pineapple
To find all fruits that have the color red in their 'colors' array field, one can query:
Fruit.all_in(:colors => ['red'])
=>[apple, pineapple]
I'm fairly new to rails, working on a Rails 3 app with a Profile model for users.
In the profile Model I'd like to have a "name" entry, and I'd like to be able to access logical variations of it using simple syntax like:
user.profile.name = "John Doe"
user.profile.name.first = "John"
user.profile.name.last = "Doe"
Is this possible, or do I need to stick with "first_name" and "last_name" as my fields in this model?
It's possible, but I wouldn't recommend it.
I would just stick with first_name and last_name if I were you and add a method fullname:
def fullname
"#{first_name} #{last_name}"
end
Edit:
If you really do want user.profile.name, you could create a Name model like this:
class Name < ActiveRecord::Base
belongs_to :profile
def to_s
"#{first} #{last}"
end
end
This allows you to do:
user.profile.name.to_s # John Doe
user.profile.name.first # John
user.profile.name.last # Doe
The other answers are all correct, in so far as they ignore the #composed_of aggregator:
class Name
attr_reader :first, :last
def initialize(first_name, last_name)
#first, #last = first_name, last_name
end
def full_name
[#first, #last].reject(&:blank?).join(" ")
end
def to_s
full_name
end
end
class Profile < ActiveRecord::Base
composed_of :name, :mapping => %w(first_name last_name)
end
# Rails console prompt
> profile = Profile.new(:name => Name.new("Francois", "Beausoleil"))
> profile.save!
> profile = Profile.find_by_first_name("Francois")
> profile.name.first
"Francois"
As noted on the #composed_of page, you must assign a new instance of the aggregator: you cannot just replace values within the aggregator. The aggregator class acts as a Value, just like a simple string or number.
I also sent a response yesterday with a very similar answer: How best to associate an Address to multiple models in rails?
As Capt. Tokyo said that's a horrible idea but here's how you would do it:
rails g model User full_name:hash
Then you would store data in it like so:
user = User.new
user.full_name = {:first => "Forrest", :last => "Gump"}
Now your problems begin.
To search the field requires both names and you can't do a partial search like searching for all people with the same last name. Worst of all you can store anything in the field! So imagine another programmer mistypes one of the field names so for a week you have {:fist => "Name", :last => "Last"} being inserted into the database! Noooooooooooooooooo!
If you used proper field names you could do this:
user = User.new(:first_name => "First", :last_name => "Last")
Easy to read and no need for hashes. Now that you know how to do it the wrong way, do it the right way. :)
FYI (assume you have a field fullname. ie your profile.name = "John Doe")
class Profile
def name
#splited_name ||= fullname.split # #splited_name would cache the result so that no need to split the fullname every time
end
end
Now, you could do something like this:
user.profile.fullname # "John Doe"
user.profile.name.first # "John"
user.profile.name.last # "Doe"
Note the following case:
user.profile.fullname = "John Ronald Doe"
user.profile.name.first # "John"
user.profile.name.second # "Ronald"
user.profile.name.last # "Doe"
I agree with captaintokyo. You won't miss out the middle names.
Also this method assume no Chinese, Japanese names are input. It's because those names contain no spaces in between first name and last name normally.