Введение в серию Ruby Social Gems
В этой серии мы расскажем о драгоценных камнях, основанных на социальных сетях и социальных сетях, таких как LinkedIn , Twitter , Facebook , Youtube и любые другие предлагаемые драгоценные камни.
LinkedIn Gem
Первая жемчужина в серии — это жемчужина LinkedIn и API-интерфейсы LinkedIn. Мы увидим, насколько простым и понятным является API LinkedIn, и как гем делает его более доступным.
Прежде чем мы начнем, я должен отметить еще одну важную жемчужину: omniauth и omniauth-linkedin. Эти драгоценные камни позволяют пользователю входить в систему с помощью своей учетной записи LinkedIn, Facebook, Twitter и т. Д. Мы посвятим учебник Omniauth позже, но в этой статье мы будем использовать Devise для создания простых учетных записей пользователей.
Демо-приложение
Приложение, которое мы собираемся создать с помощью самоцвета LinkeIn, довольно простое. Мы получим все пользовательские данные из LinkedIn в наших моделях приложений rails, чтобы мы могли отображать их в любом формате, который нам нужен.
Начиная с приложения:
Вы можете скачать полный исходный код формы github здесь
Создайте новое приложение rails:
rails new rsg_linkedin_gem
Добавьте Gem, devise, bootstrap gems в path/to/project/Gemfile
gem ‘devise’ | |
gem ‘linkedin’ | |
gem ‘twitter-bootstrap-rails’ |
А потом беги
bundle install
Мы собираемся использовать начальную загрузку для компонента пользовательского интерфейса.
Инициализация
Прежде чем начать, нам нужно выполнить несколько команд для инициализации проекта.
Создание пользовательской модели и стиля Bootstrap
Следующие команды находятся на странице github проекта devise и проекта начальной загрузки Twitter.
Чтобы установить устройство
rails generate devise:install
Создать пользовательскую модель
rails generate devise user
Чтобы настроить представления
rails generate devise:views
Чтобы установить загрузчик
rails g bootstrap:install
Чтобы установить макет начальной загрузки
rails g bootstrap:layout application fixed
Удалить индексный файл из
path/to/project/public/index.html
Структура приложения
Контроллеры
Нам потребуется только создать один контроллер, который будет обрабатывать соединение с LinkedIn. Контроллер будет извлекать данные из API и передавать их нашим моделям.
rails g controller linkedin
Добавьте следующую строку в начале контроллера linkedin
before_filter :authenticate_user! |
Мы добавим несколько вспомогательных методов для обработки запросов аутентификации и API.
Во-первых, и прежде чем углубляться в какие-либо методы, мы должны определить хэш конфигурации. Хеш содержит всю информацию для согласования соединения с API-интерфейсами LinkedIn. Элемент request_token_path
предоставляет разрешения для доступа к различным частям API, таким как r_fullprofile
для полного профиля или r_network
для соединений.
Вы можете добавить больше токенов к элементу request_token_path
, связав их знаком +
, например:
/uas/oauth/requestToken?scope=r_basicprofile+r_fullprofile+r_emailaddress+r_network
Полный объект, который мы добавим вверху контроллера LinkedIn, находится ниже:
@@config = { | |
:site => ‘https://api.linkedin.com’, | |
:authorize_path => ‘/uas/oauth/authenticate’, | |
:request_token_path => ‘/uas/oauth/requestToken?scope=r_basicprofile+r_fullprofile’, | |
:access_token_path => ‘/uas/oauth/accessToken’ | |
} |
Объект LinkedinOauthSetting используется для хранения токена доступа и доступа к секрету.
Цель метода generate_linkedin_oauth_url
состоит в том, чтобы сгенерировать URI аутентификации linkedin, который запрашивает у пользователя разрешения. Метод сначала проверяет, существует ли объект для текущего пользователя. Если нет, то он создаст клиентский объект linkedin и создаст объект request_token
с помощью oauth_callback
. Этот обратный вызов является методом, который будет вызван после того, как пользователь предоставит доступ. Теперь сохраните request_token.token
и request_token.secret
в сеансе, поскольку они будут использоваться для создания постоянных токенов доступа. Наконец, перенаправьте пользователя на authorize_url
. Если пользователь уже был здесь, он перенаправит его непосредственно в действие /oauth_account
.
generate_linkedin_oauth_url
def generate_linkedin_oauth_url | |
if LinkedinOauthSetting.find_by_user_id(current_user.id).nil? | |
client = LinkedIn::Client.new(‘your-api-key’, ‘your-secret-key’, @@config) | |
request_token = client.request_token(:oauth_callback => «http://#{request.host}:#{request.port}/oauth_account») | |
session[:rtoken] = request_token.token | |
session[:rsecret] = request_token.secret | |
redirect_to request_token.authorize_url | |
else | |
redirect_to «/oauth_account» | |
end | |
end |
Метод аутентификации, который устанавливается в качестве обратного вызова в объекте request_token
, аутентифицирует пользователя в первый раз. Если пользователь уже аутентифицирован, он будет перенаправлять пользователя домой без каких-либо действий.
oauth_account
def oauth_account | |
client = LinkedIn::Client.new(‘your-api-key’, ‘your-secret-key’, @@config) | |
pin = params[:oauth_verifier] | |
if pin | |
atoken, asecret = client.authorize_from_request(session[:rtoken], session[:rsecret], pin) | |
LinkedinOauthSetting.create!(:asecret => asecret, :atoken => atoken, :user_id => current_user.id) | |
end | |
redirect_to «/» | |
end |
Во-первых, мы создаем клиентский объект linkedin с нашими ключами (‘your-api-key’, ‘your-secret-key’), которые вы получаете после регистрации приложения в подключенном api . Если существуют параметры oauth_verifier
, которые передаются LinkedIn, пользователь предоставил доступ к приложению, поэтому мы авторизуем клиента. Когда мы авторизируемся в первый раз, нам нужно сохранить и получить токен доступа и секрет, чтобы получить их позже.
get_client
просто возвращает авторизованный клиентский объект linkedin. Здесь объект linkedin_oauth_setting
извлекается из базы данных и авторизует клиентский объект.
get_client
def get_client | |
linkedin_oauth_setting = LinkedinOauthSetting.find_by_user_id(current_user.id) | |
client = LinkedIn::Client.new(‘iv6uehul4g5m’, ‘wtMfG2MbFerSULTC’, @@config) | |
client.authorize_from_access(linkedin_oauth_setting.atoken, linkedin_oauth_setting.asecret) | |
client | |
end |
Вот корневое действие. Он проверяет, есть ли у этого пользователя настройка «oauth». Если это так, он перенаправит их на действие linkedin_profile.
index
def index | |
unless LinkedinOauthSetting.find_by_user_id(current_user.id).nil? | |
redirect_to «/linkedin_profile» | |
end | |
end |
Здесь мы показываем простую HTML-страницу данных, извлеченных из API-интерфейсов linkedin.
linkedin_profile
def linkedin_profile | |
basic_profile = get_basic_profile | |
full_profile = get_full_profile | |
positions = get_positions | |
educations = get_educations | |
end |
Маршруты
Добавьте следующее в path/to/project/config/routes
resources :linkedin | |
match ‘/linkedin_profile’ | |
match ‘/oauth_account’ => «linkedin#oauth_account» | |
match ‘/linkedin_oauth_url’ => ‘linkedin#generate_linkedin_oauth_url’ | |
root :to => ‘linkedin#index’ |
Взгляды
Мы должны сделать несколько изменений перед запуском сервера.
Измените path/to/project/app/views/layouts/application.html.erb
представления макета path/to/project/app/views/layouts/application.html.erb
удалив следующий блок 65-75
, а затем заменив следующие строки 50-52
на
<li><%= link_to current_user.email, «/users/edit» %></li> | |
<li><%= link_to «Sign out», «/users/sign_out», :method => «DELETE» %></li> |
Измените представление индекса [путь / к / проекту / приложению / views / linkedin / index.html.erb]:
<h1>Linkedin Application</h1> | |
<a href=»/linkedin_oauth_url» class=»btn btn-primary btn-larg«>Connect to LinkedIn</a> |
модели
Мы должны остановиться здесь, чтобы взглянуть на API-интерфейсы LinkedIn и на то, что мы рассмотрим здесь. Мы также изучим спецификацию моделей, которые нам нужно создать в нашем приложении.
Сайт разработчиков LinkedIn — это лучшее место, это краткое руководство является исчерпывающим. В руководстве показано, как создать приложение на LinkedIn, а также как получить ключ API и секретный ключ (которым вы никогда не должны делиться ни с кем).
Вы увидите демонстрацию того, как соединиться со скриптом ruby без каких-либо драгоценных камней, что занимает гораздо больше времени, чем драгоценный камень.
В таблице на странице Аутентификация перечислены разрешения, которые мы увидим, как их использовать позже.
Вот несколько из них:
разрешение | Сфера |
---|---|
Ваш профиль Обзор | r_basicprofile |
Ваш полный профиль | r_fullprofile |
Ваша электронная почта | r_emailaddress |
Ваши связи | r_network |
Мы сфокусируемся на части API полей профиля , потому что не можем охватить весь API. Я думаю, вы получите хорошее представление о том, как работает самоцвет, написав это демо-приложение.
Давайте сначала сосредоточимся на полях базового профиля . Это будет первая часть API, которая будет привязана к нашему приложению rails.
LinkedinOauthSetting
Это важная модель, в которой для каждого пользователя хранятся два важных значения, которые разрешают доступ к его учетной записи без запроса разрешения каждый раз.
Выполните следующие команды для генерации вышеуказанной модели:
rails g model linkedin_oauth_setting atoken:string asecret:string user_id:integer
rake db:migrate
Не забывайте всегда проверять эту строку над каждой таблицей «Для этих полей требуется разрешение члена r_basicprofile », чтобы использовать эти параметры разрешения позже.
Добавьте ассоциацию к модели linkedin_oauth_setting:
path/to/project/app/models/linkedin_oauth_setting.rb
belongs_to :user |
BasicProfile
Выберите несколько атрибутов для добавления в модель, и вот их список:
поле | Описание |
---|---|
Имя | имя участника |
фамилия | фамилия участника |
девичья фамилия | девичья фамилия участника |
отформатирован имя | имя участника отформатировано на основе языка |
Заголовок | заголовок участника (часто «Должность в компании») |
название местоположения) | Общее название местоположения члена LinkedIn (например: «Область залива Сан-Франциско») |
промышленность | отрасль, в которой участник LinkedIn указал свой профиль (отраслевые коды) |
резюме | Длинная текстовая область, где участник описывает свой профессиональный профиль |
специальности | Краткая текстовая область, где участник перечисляет свои специальности |
фото гиперссылка | URL-адрес изображения профиля, если участник связал его со своим профилем, и он виден запрашивающей стороне |
общественные профильный URL | URL-адрес общедоступного профиля участника, если он включен |
Теперь выполните следующую команду, чтобы создать таблицу basic_profiles
:
rails g model basic_profile first_name:string last_name:string maiden_name:string formatted_name:string headline:string location:string industry:string summary:string specialties:string picture_url:string public_profile_url:string user_id:integer
rake db:migrate
Добавьте ассоциацию к модели basic_profile:
path/to/project/app/models/basic_profile.rb
belongs_to :user |
FullProfile
Выбрав несколько атрибутов для добавления в модель, вы заметите, что таблица full_profile содержит много других сложных объектов, таких как ( publications
, patents
, languages
, skills
и т. Д.). Мы собираемся создать отдельные модели для нескольких из них. Вот их список:
поле | Описание |
---|---|
ассоциации | Краткая текстовая область, перечисляющая Ассоциации, которые имеет член |
почести | Краткая текстовая область с описанием почестей, которые может иметь участник |
интересы | Краткая текстовая область с описанием интересов участника |
Теперь выполните следующую команду, чтобы создать таблицу full_profiles
:
rails g model full_profile associations:string honors:string interests:string user_id:integer
rake db:migrate
Добавьте ассоциацию к модели full_profile:
path/to/project/app/models/full_profile.rb
belongs_to :user | |
has_many :educations | |
has_many :positions |
Позиция
Давайте добавим несколько атрибутов в модель:
поле | Описание |
---|---|
заглавие | должность, занимаемая на должности, указанной участником |
резюме | краткое изложение позиции члена |
Дата начала | структурированный объект с полями месяца и года, указывающими, когда началась позиция |
Дата окончания | структурированный объект с полями месяца и года, указывающими, когда позиция закончилась |
это тока | значение «истина» или «ложь», в зависимости от того, отмечено ли оно текущим |
Компания | компания, в которой работает участник |
Теперь выполните следующую команду, чтобы создать таблицу positions
:
rails g model position title:string summary:string start_date:date end_date:date is_current:boolean company:string full_profile_id:integer
rake db:migrate
Добавьте ассоциацию к модели позиции:
path/to/project/app/models/position.rb
belongs_to :full_profile |
образование
Для модели образования у нас есть:
поле | Описание |
---|---|
название школы | название школы, указанное участником |
область изучения | область обучения в школе, как указано участником |
Дата начала | структурированный объект поле года, указывающее, когда началось образование |
Дата окончания | структурированный объект с полем года, указывающим, когда закончилось образование |
степень | строка, описывающая степень, если таковая имеется, полученную в этом учреждении |
виды деятельности | строка, описывающая действия, в которых участник принимал участие, будучи студентом в этом учреждении |
Примечания | строка, описывающая другие детали исследований участника |
Теперь выполните следующую команду для создания таблицы educations
:
rails g model education school_name:string field_of_study:string start_date:date end_date:date degree:string activities:string notes:string full_profile_id:integer
rake db:migrate
Добавьте ассоциацию к модели:
path/to/project/app/models/education.rb
belongs_to :full_profile |
пользователь
Добавьте ассоциацию к модели:
path/to/project/app/models/user.rb
has_one :basic_profile | |
has_one :full_profile | |
has_one :linkedin_oauth_setting |
Запросы API-интерфейсов LinkedIn
Теперь в контроллере linkedin есть необходимые вспомогательные методы для аутентификации. Мы сохранили необходимые токены для последующего доступа, поэтому пришло время написать несколько вспомогательных методов для запроса API. Мы будем использовать модельные объекты для этой части.
Запросить API-интерфейсы очень просто. После авторизации объекта client вы вызываете метод profile
для объекта и передаете все поля, которые хотите получить, например:
client.profile(:fields => [:first_name, :last_name, :maiden_name , :formatted_name ,:headline])
Следующие методы используются для извлечения данных из API и передачи их в модели рельсов. Как видите, мы создаем объект с помощью извлеченного объекта json из API с несколькими настройками.
get_basic_profile
def get_basic_profile | |
bprofile = BasicProfile.find_by_user_id(current_user.id) | |
if bprofile.nil? | |
client = get_client | |
profile = client.profile(:fields => [«first-name», «last-name», «maiden-name», «formatted-name» ,:headline, :location, :industry, :summary, :specialties, «picture-url», «public-profile-url»]) | |
basic_profile = profile.to_hash | |
basic_profile[:location] = basic_profile[«location»][«name»] | |
new_basic_profile = BasicProfile.new(basic_profile) | |
new_basic_profile.user = current_user | |
new_basic_profile.save | |
new_basic_profile | |
else | |
bprofile | |
end | |
end |
get_full_profile
def get_full_profile | |
fprofile = FullProfile.find_by_user_id(current_user.id) | |
if fprofile.nil? | |
client = get_client | |
full_profile = client.profile(:fields => [:associations, :honors, :interests]) | |
full_profile = full_profile.to_hash | |
new_full_profile = FullProfile.new(full_profile) | |
new_full_profile.user = current_user | |
new_full_profile.save | |
new_full_profile | |
else | |
fprofile | |
end | |
end |
get_positions
def get_positions | |
positions = Position.find_all_by_full_profile_id(current_user.full_profile.id) | |
if positions.empty? | |
client = get_client | |
positions = client.profile(:fields => [:positions]).positions.all | |
positions.each do |p| | |
if p.is_current == «true» | |
Position.create( | |
title: p.title, | |
summary: p.summary, | |
start_date: Date.parse(«1/#{p.start_date.month ? p.start_date.month : 1}/#{p.start_date.year}«), | |
end_date: Date.parse(«1/#{p.end_date.month ? p.end_date.month : 1}/#{p.end_date.year}«), | |
is_current: p.is_current, | |
company: p.company.name, | |
full_profile_id: current_user.full_profile.id) | |
else | |
Position.create( | |
title: p.title, | |
summary: p.summary, | |
start_date: Date.parse(«1/#{p.start_date.month ? p.start_date.month : 1}/#{p.start_date.year}«), | |
is_current: p.is_current, | |
company: p.company.name, | |
full_profile_id: current_user.full_profile.id) | |
end | |
end | |
current_user.full_profile.positions | |
else | |
positions | |
end | |
end |
get_educations
def get_educations | |
educations = Education.find_all_by_full_profile_id(current_user.full_profile.id) | |
if educations.empty? | |
client = get_client | |
educations = client.profile(:fields => [:educations]).educations.all | |
educations.each do |e| | |
new_educations = Education.create( | |
school_name: e.school_name, | |
field_of_study: e.field_of_study, | |
start_date: Date.parse(«1/#{e.end_date.month ? p.end_date.month : 1}/#{e.end_date.year}«), | |
end_date: Date.parse(«1/#{e.end_date.month ? p.end_date.month : 1}/#{e.end_date.year}«), | |
degree: e.degree, | |
activities: e.activities, | |
notes: e.notes, | |
full_profile_id: current_user.full_profile.id) | |
end | |
current_user.full_profile.educations | |
else | |
educations | |
end | |
end |
Есть несколько примеров в репозитории gem на github, например:
# update status for the authenticated user | |
client.update_status(‘is playing with the LinkedIn Ruby gem’) | |
# clear status for the currently logged in user | |
client.clear_status | |
# get network updates for the authenticated user | |
client.network_updates | |
# get profile picture changes | |
client.network_updates(:type => ‘PICT’) | |
# view connections for the currently authenticated user | |
client.connections |
Давайте соединим все это и создадим простое представление для отображения в нашем приложении для отображения сохраненных данных.
Вот path/to/project/linkedin/linkedin_profile.html.erb
просмотра path/to/project/linkedin/linkedin_profile.html.erb
<div class=»row«> | |
<div class=»span4«> | |
<div class=»thumbnail«> | |
<img src=»<%= @basic_profile.picture_url %>» style=»float: left;margin: 5px;«> | |
<h3><%= @basic_profile.formatted_name %></h3> | |
<h4><%= @basic_profile.headline %></h4> | |
<br> | |
<p><%= @basic_profile.summary %></p> | |
</div> | |
</div> | |
<div class=»span4«> | |
<div class=»well«> | |
<h5>Interests</h5> | |
<p><%= @full_profile.interests %></p> | |
<br> | |
<h5>Associations</h5> | |
<p><%= @full_profile.associations %></p> | |
<br> | |
<h5>Honors</h5> | |
<p><%= @full_profile.honors %></p> | |
<br> | |
</div> | |
</div> | |
</div> | |
<div class=»row» style=»margin-top: 16px;«> | |
<div class=»span10«> | |
<h1>Positions</h1> | |
<table class=»table table-striped«> | |
<tr> | |
<th>Title</th> | |
<th>Summary</th> | |
<th>Company Name</th> | |
<th>Is Current</th> | |
<th>Start Date</th> | |
<th>End Date</th> | |
</tr> | |
<% @positions.each do |p| %> | |
<tr> | |
<th><%= p.title %></th> | |
<th><%= p.summary %></th> | |
<th><%= p.company %></th> | |
<th><%= p.is_current %></th> | |
<th><%= p.start_date %></th> | |
<th><%= p.end_date %></th> | |
</tr> | |
<% end %> | |
</table> | |
</div> | |
</div> | |
<div class=»row» style=»margin-top: 16px;«> | |
<div class=»span10«> | |
<h1>Educations</h1> | |
<table class=»table table-striped«> | |
<tr> | |
<th>School Name</th> | |
<th>Field of Study</th> | |
<th>Degree</th> | |
<th>Activities</th> | |
<th>Notes</th> | |
<th>Start Date</th> | |
<th>End Date</th> | |
</tr> | |
<% @educations.each do |e| %> | |
<tr> | |
<th><%= e.school_name %></th> | |
<th><%= e.field_of_study %></th> | |
<th><%= e.degree %></th> | |
<th><%= e.activities %></th> | |
<th><%= e.notes %></th> | |
<th><%= e.start_date %></th> | |
<th><%= e.end_date %></th> | |
</tr> | |
<% end %> | |
</table> | |
</div> | |
</div> |
Завершение
Что ж, я надеюсь, что это руководство будет полезным, и будет хорошим введением в использование гема LinkedIn и API в целом, если вы хотите предложить следующий гем, который мы рассмотрим, мы его выполним и спасибо за чтение.