Missing and inaccurate payload in Rails with ActiveModel and Forms - ruby-on-rails

I have a model for Organisation like
class Organisation
include ActiveModel::Model
attr_accessor :orguid,
:title, :firstname, :lastname, :role, :telephone, :extension, :email,
:name, :branch, :address1, :address2, :address3, :city, :state, :country, :zip
end
In my controller I have the following actions:
# frozen_string_literal: true
require 'cgi'
require 'json'
class OrganisationsController < ApplicationController
include Secured
before_action :set_api, only: %i[dashboard create]
before_action :user_info, only: %i[dashboard register]
def dashboard
#registration = #api.registered?
end
def register
#organisation = Organisation.new
end
def create
organisation_params
register_data = params[:organisation].to_h
register_data['oruid'] = org_uid
#api.register(register_data)
end
private
def set_api
#api = CoreApi.new(org_uid)
end
def user_info
#user_info = session[:userinfo].to_h
end
def org_uid
CGI.escape(user_info['uid'])
end
def organisation_params
params.require(:organisation).permit!
end
end
in my register.html.erb I have:
<h1> Register Your Organisation</h1>
<%= form_with model: #organisation, url: org_register_path do |f| %>
<div class="container">
<h2>Your Details</h2>
<div class="form-row">
<div class="form-group col-md-2">
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
</div>
<div class="form-group col-md-5">
<%= f.label :first_name %>
<%= f.text_field :firstname, class: 'form-control' %>
</div>
<div class="form-group col-md-5">
<%= f.label :last_name %>
<%= f.text_field :lastname, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<%= f.label :role %>
<%= f.text_field :role, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<%= f.label :telephone %>
<%= f.telephone_field :telephone, class: 'form-control' %>
</div>
<div class="form-group col-md-2">
<%= f.label :extension %>
<%= f.text_field :extension, class: 'form-control' %>
</div>
<div class="form-group col-md-6">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control', readonly:'', value: #user_info['info']['name'] %>
</div>
</div>
</div>
<div class="container">
<h2>Organisation Details</h2>
<div class="form-row">
<div class="form-group col-md-6">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group col-md-6">
<%= f.label :branch %>
<%= f.text_field :branch, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<%= f.label :address_line_1 %>
<%= f.text_field :address1, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<%= f.label :address_line_2 %>
<%= f.text_field :address2, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<%= f.label :address_line_3 %>
<%= f.text_field :address3, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<%= f.label :city %>
<%= f.text_field :city, class: 'form-control' %>
</div>
<div class="form-group col-md-4">
<%= f.label :state %>
<%= f.text_field :state, class: 'form-control' %>
</div>
<div class="form-group col-md-4">
<%= f.label :country %>
<%= f.text_field :country, class: 'form-control' %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-2">
<%= f.label :zip %>
<%= f.text_field :zip, class: 'form-control' %>
</div>
</div>
</div>
<div class="container">
<div class="form-row">
<div class="form-group col-md-12">
<%= f.button :Register, class: 'btn btn-primary' %>
</div>
</div>
</div>
<% end %>
and finally the register method in my core_api.rb is this:
def register(data)
body = data.to_json
puts ">> >> >> >> #{body.class} :: #{body}"
options = { headers: { 'Content-Type' => 'application/json' }, body: body }
response = self.class.post('/organisations', options)
#puts ">>>>>>>>>>>> #{response}"
end
and finally my routes.rb file contains:
Rails.application.routes.draw do
get '/' => 'home#show'
get '/auth/auth0/callback' => 'auth0#callback'
get '/auth/failure' => 'auth0#failure'
get '/logout', to: 'logout#logout', as: 'logout'
get '/organisations/dashboard', to: 'organisations#dashboard', as: 'org_dashboard'
get '/organisations/register', to: 'organisations#register', as: 'org_register'
post '/organisations/register', to: 'organisations#create'
root 'home#show'
end
now when I run the server and submit the form in the logs I get:
>> >> >> >> String :: {"title":"","firstname":"","lastname":"","role":"","telephone":"","extension":"","email":"alijy3#yahoo.com","name":"we","branch":"we","address1":"we","address2":"","address3":"","city":"we","state":"","country":"we","zip":"","oruid":"auth0%7C5e5388493d670c11be833bca","contact_id":0}
which to me looks like a proper json. But, since the api response was continually unsuccessful I intercepted the outgoing post with Postman to see what payload is being sent. To my surprise the payload is not flat json, but comes out like this:
I have 2 problems with this:
The api accepts items like address1, address2, city, etc. I believe I should send those rather than the currently showing organisation[address1], organisation[address2], etc.
The second problem is that I add the orguid after the form is submitted and before calling/posting to the api. But, although I can see it in the log messages, I don't see the orguid in the postman payload in any form.
I don't have any database on the server. Everything is fetch/posted/saved through the api. I've been reading about how to work with Activemodel and forms for a while and I haven't managed to get this resolved yet. Any help or explanation would be much appreciated.

No offense but this is a train wreck. You don't need to break every rails convention just because you're not using ActiveRecord in this specific case.
Start off by using ActiveModel::Attributes#attribute instead of Ruby's built in attr_accessor.
class Organisation
include ActiveModel::Model
include ActiveModel::Attributes
[:orguid, :title, :firstname, :lastname, :role, :telephone,
:extension, :email, :name, :branch,
:address1, :address2, :address3, :city, :state, :country, :zip]
.each do |name|
attribute name
end
# #todo write validations!
end
This creates attributes that act like ActiveRecord attributes and you can serialize the model properly with #organization.as_json.
Then lets just start fresh on that controller as there is just too much smell for it to be worth salvaging.
# routes.rb
resources :organisations, only: [:new, :create]
class OganizationsController < ApplicationController
# GET /organizations/new
def new
#organization = Organization.new
end
# POST /organizations
def create
# You never manually parse out incoming params - thats Rack's job.
# also since you have a model - USE IT!
#organization = Organization.new(organization_params) do |o|
o.orguid = org_uid
end
# validate the user input before you send it to an external API
if #organization.valid? && #api.register(#organization)
redirect_to '/somewhere'
else
render :new
end
end
private
# use monads here instead of callbacks!
def user_info
# Rails will serialize/deserialize hashes automatically
# from the session
session[:userinfo]
end
def org_uid
# Have no clue what the heck you're doing with CGI escape.
#org_uid ||= user_info['uid']
end
def api
#api ||= CoreApi.new(org_uid)
end
def organization_params
# You don't have any reason to use 'permit!' and give
# yourself a potential mass assignment vunerablity
params.require(:organization)
.permit(
:title, :firstname, :lastname, :role, :telephone,
:extension, :email, :name, :branch,
:address1, :address2, :address3, :city,
:state, :country, :zip
)
end
end
Rename the view /organizations/new.html.rb. At this point you should be able to stub out the API and do an integration test with valid and invalid input.
That whole session[:userinfo] thing still smells really bad - if you are taking the response from OAuth and shoving it into the session your setting yourself up for a really bad time as that can cause cookie overflows. Also in general in Rails if you're ever manually casting/serializing then its a really good sign that your doing something very wrong.
Have no clue really whats going on in your CoreApi class but if you are using HTTParty you should not do ANY manual JSON encoding.
# #fixme name is way to generic.
class CoreApi
include HTTParty
format :json # sets content type and encodes the content
# ...
def register(organization)
response = self.class.post('/organisations', #organization.as_json)
if response.success?
true
else
#organization.errors.add(:base, 'Could not be registered')
false
end
end
end

Related

How to display a form field whose role is of enum datatype and is stored as integer in the database. The user can't change the role

My profile role is created and when the user logs in the profile controller's edit action view will be displayed. I want to show the role that is assigned to user in the edit action and the user cannot change the role. My edit.html.erb file is given as:
<div class="row">
<div class="col-md-6 offset-md-3">
<h3>Profile</h3>
<%= form_for(#profile) do |f| %>
<div class="form-group">
<%= f.label :first_name %><br />
<%= f.email_field :first_name, autofocus: true, class: "form-control"%>
</div>
<div class="form-group">
<%= f.label :last_name %><br />
<%= f.password_field :last_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :role %><br />
<%= f.select(:role, [['User', 'user'], ['Vip', 'vip'], ['Admin', 'admin']]) %>
</div>
<div class="actions form-group">
<%= f.submit "Submit", class: 'btn btn-primary' %>
</div>
<% end %>
</div>
The simplest possible way is just to use String#humanize from ActiveSupport.
Capitalizes the first word, turns underscores into spaces, and (by
default)strips a trailing '_id' if present. Like titleize, this is
meant for creating pretty output.
irb(main):008:0> roles.roles.keys.map(&:humanize)
=> ["User", "Vip", "Admin"]
irb(main):009:0> Profile.new(role: :admin).role.humanize
=> "Admin"
Profile.roles gives us the hash mapping for the Enum.
You can use this to generate the select tag with:
<%= form.select :role, Profile.roles.keys.map{|k| [k.humanize, k] } %>
You can get "vip".humanize to return "VIP" by setting up an inflection:
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'VIP'
end
This may require restarting your Rails server before it kicks in.
Using the I18n module
But if you want a more flexible solution that lets you set the mappings yourself (and works with translations) use the I18n module:
# config/locales/en.yml
en:
activerecord:
attributes:
profile:
roles:
user: 'User'
vip: 'Very Important Person'
admin: 'Admin'
# app/helpers/users_helper.rb
module UsersHelper
def translate_role(role)
I18n.t("activerecord.attributes.user.roles.#{ role }", default: role.humanize)
end
def role_options
Profile.roles.keys.map{|k| [translate_role(k), k] }
end
end
You would then display the users role by:
<%= translate_role(#user.role) %>
And you can setup the form input as:
<%= form.select :role, role_options %>
You can use a helper method, For example in the application_helper.rb you can make a method like this:
class ApplicationHelper
def profile_role(profile)
# Perform your logic
# if you are using as_enum gem for example
Profile.roles.select{|symbol_role,integer_rep| integer_rep == profile.role}.keys.first.to_s
# of course there could be much better way to get the string.
end
end
Then in your view, If user should not be able to change it, there is no need to make it as drop-down list:
<div class="row">
<div class="col-md-6 offset-md-3">
<h3>Profile</h3>
<%= form_for(#profile) do |f| %>
<div class="form-group">
<%= f.label :first_name %><br />
<%= f.email_field :first_name, autofocus: true, class: "form-control"%>
</div>
<div class="form-group">
<%= f.label :last_name %><br />
<%= f.password_field :last_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :role %><br />
<%= text_field_tag 'role', profile_role(#profile), disabled: true %>
</div>
<div class="actions form-group">
<%= f.submit "Submit", class: 'btn btn-primary' %>
</div>
<% end %>
You can just show it as regular text, e.g.:
...
<div class="form-group">
<%= f.label :last_name %><br />
<%= f.password_field :last_name, class: "form-control" %>
</div>
<p>
Role:<br />
<%= #profile.role %>
</div>
<div class="actions form-group">
<%= f.submit "Submit", class: 'btn btn-primary' %>
</div>
...

validates_confirmation_of :password does not work [ruby 4.2]

validates_confirmation_of :password does not work when I submitted my form. Even if the password confirmation is not the same, the user is signed up.
I wrote the same thing that the guide. during my research , I did not found anything that explain that.
Do you know what is happening and how can I solve it?
Here is my code:
My view:
<%= form_for User.new do |f| %>
<div class="row">
<div class="col-md-6">
<%= f.label :Prénom %> :
<%= f.text_field :first_name, class: "form-control" %><br />
</div>
<div class="col-md-6">
<%= f.label :Nom %> :
<%= f.text_field :last_name, class: "form-control" %><br />
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= f.label :Pseudo %> :
<%= f.text_field :user_name, class: "form-control"%><br />
</div>
<div class="col-md-6">
<%= f.label :Email %> :
<%= f.email_field :email, class: "form-control" %><br />
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= f.label :Mot_de_passe %> :
<%= f.password_field :password, class: "form-control" %><br />
</div>
<div class="col-md-6">
<%= f.label :Confirmation_mot_de_passe %> :
<%= f.password_field :password_confirmation, class: "form-control" %><br />
</div>
</div>
<%= f.label :Club_favori %> :
<%=f.select(:club) do%>
<%= options_from_collection_for_select(Club.all,:id ,:name) %>
<% end %>
<br>
<%= f.submit class: "btn btn-primary" %>
<% end %>
My model:
class User < ActiveRecord::Base
has_merit
has_secure_password
has_many :comments
validates_length_of :password, minimum: 5, too_short: 'please enter at least 5 characters', on: :create
validates_presence_of :user_name, :message => 'Vous devez remplir tout les champs.', on: :create
validates_uniqueness_of :user_name, :case_sensitive => false, :message => "Ce pseudo n'est pas disponible.", on: :create
validates_confirmation_of :password, on: :create
end
My controller:
class UsersController < ApplicationController
def create
#user = User.new(user_params)
if #user.save
#user.add_badge(1)
session[:user_id] = #user.id
redirect_to '/feed'
else
redirect_to '/signup', flash: {error_message: #user.errors}
end
end
private
def user_params
params.require(:user).permit( :user_name, :first_name, :last_name, :email, :password, :sash, :club)
end
def new
#user = User.new
#clubs =Club.all
end
end
Thank you in advance for your help.
You override your current #user when you enter your form.
Just change:
<%= form_for User.new do |f| %>
to
<%= form_for #user do |f| %>

How to use mongoid-paperclip to upload multiple images through nested model?

I have a rails app where I am trying to upload multiple images using nested_attributes but am running into great difficulty. The images don't seem to be saving to mongodb. I have followed this tutorial (though it seems lacking in detail): http://initializd.com/blog/2013/3/upload-multiple-files-with-html5-rails-mongoid-paperclip-and-google-cloud-storage
Basically, I have a form where a user is able to submit multiple listings (as nested attributes), and under each listing they are able to submit multiple images (also as nested attributes).
Here is my form:
The important part is the file_field_tag where the user is supposed to upload multiple images.
<%= nested_form_for #user, url: wizard_path, :html => { :multipart => true } do |f| %>
<h1 style="margin-bottom: 6%;"> Add Listings </h1>
<!-- nested fields -->
<%= f.fields_for :listings do |builder| %>
<div class="field form-group">
<%= builder.label :type %> <br />
<%= builder.select :type, options_for_select(listing_types), {}, { :class => 'form-control', :required => 'true' } %>
</div>
<div class="field form-group">
<%= builder.label :title %> <br />
<%= builder.text_field :title, class: 'form-control', required: 'true' %> <br />
</div>
<div class="field form-group">
<%= builder.label :description %> <br />
<%= builder.text_area :description, class: 'form-control', required: 'true' %>
</div>
<div class="field form-group">
<%= builder.label :url %> <br />
<%= builder.text_field :url, class: 'form-control', required: 'true' %>
</div>
<div class="field form-group">
<%= builder.label :zipcode %> <br />
<%= builder.text_field :zipcode, class: 'form-control', size: '24x4', required: 'true' %>
</div>
<div class="field form-group">
<%= label_tag "upload images" %> <br />
<%= file_field_tag('listing_images_attributes_file', multiple: true, name: "user[listings_attributes][images_attributes][][image]", :required => 'true') %>
</div>
<div class="field form-group">
<%= builder.link_to_remove "Remove this listing", :onclick =>"myFunction(this)" %>
<hr style="height: 2px; background-color: lightgray;">
</div>
<% end %>
<p style="margin-bottom: 15px;"><%= f.link_to_add "Add a listing", :listings %></p>
<div class="actions">
<%= f.submit "Continue", class: "btn btn-lg btn-primary" %>
</div>
<% end %>
Here are my models:
Listing Model:
class Listing
include Mongoid::Document
include Mongoid::Timestamps
field :title, type: String
field :type, type: String
field :description, type: String
field :url, type: String
field :zipcode, type: String
# association between listing and user
embedded_in :user
# each listing has many images
embeds_many :images, :cascade_callbacks => true
accepts_nested_attributes_for :images, :allow_destroy => true
end
Image Model:
class Image
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paperclip
field :listing_id, type: Integer # what is the purpose of this field exactly?
embedded_in :listing
has_mongoid_attached_file :image,
:path => ":rails_root/public/images/:id/:filename",
:url => "/images/:id/:filename"
end
Snippet from user controller update action (basically my create):
def update
#user = current_user
#have to include steps to validate zip code
case step
when :personal
#user.update_attributes(user_params)
when :listings
# should I build a listing as a default input?
# listing = #user.listings.build
#user.update_attributes(user_params)
end
render_wizard #user
end
def user_params
params.require(:user).permit(:first_name, :last_name, :zipcode, :bio, listings_attributes: [:title, :type, :description, :url, :zipcode,
{ images_attributes: [:image] }, :_destroy, :id])
end
Basically I am trying to get a user to be able to upload multiple listings, then multiple images under each listing. I wonder if this is possible using nested_attributes or will I have to handle the params manually? Also wondering whether my strong params are setup correctly. Here is a snippet from my server logs to show what my params look like:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"HUpgUfukx3Rqb2Ye3su1/9ts4byC1BFrB3HOLXgQeJr8Vrcf9JyQYvR52FC5psLPZGD2x2DlzmlQRRgEXQWo2g==", "user"=>{"listings_attributes"=>{"0"=>{"type"=>"Airbnb", "title"=>"test", "description"=>"test", "url"=>"test", "zipcode"=>"test", "_destroy"=>"false", "id"=>"57a2b9ba9cd25d2d94110543"}}}, "listing"=>{"images_attributes"=>[{"image"=>#<ActionDispatch::Http::UploadedFile:0x000001016c2b20 #tempfile=#<Tempfile:/var/folders/vp/4hffkvd52gd317mgfqczqspm0000gn/T/RackMultipart20160804-11668-1fjlflq.jpg>, #original_filename="event1.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"listing[images_attributes][][image]\"; filename=\"event1.jpg\"\r\nContent-Type: image/jpeg\r\n">}]}, "commit"=>"Continue", "id"=>"listings"}
Sorry for the long description, but I was really hoping someone could answer this question. Thank you so much!

Can't save nested model on polymorphic association

Forced to ask for help with saving nested models on polymorphic association. I'm missing something but can't figure out what.
Everithing pretty straightforward. There is Address which can have multiple Phones.
So models are
class Address < ActiveRecord::Base
has_many :phones, as: :phoneable
accepts_nested_attributes_for :phones, allow_destroy: true
validates :city, :street, :building, :name, presence: true
end
and
class Phone < ActiveRecord::Base
belongs_to :phoneable, polymorphic: true
validates :number, :extension, presence: true
end
addresses_controller.rb
def new
#address = Address.new
#phone = #address.phones.build
authorize #address
end
def create
#address = Address.create(address_params)
authorize #address
if #address.save
binding.pry
flash[:success] = "Address #{#address.name} created"
redirect_to address_path(#address)
else
flash.now[:danger] = 'Failed'
render :new
end
end
def address_params
params.require(:address).permit(:name, :street, :building, :city, phones_attributes: [:id, :number, :extension, :details] )
end
/app/views/address.html.erb
<div class="row">
<div class="col-md-12">
<%= form_for(#address, html: {class: 'form-horizontal', role: 'form'}) do |f| %>
<%= render 'shared/errors', obj: #address, model_name: 'addresses' %>
<div id="create-form">
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :city, 'Город' %>
</div>
<div class="col-md-4">
<%= f.select(:city, options_for_select(['Moscow', 'Samara']), {}, {class: "form-control"}) %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :street, 'Street' %>
</div>
<div class="col-md-4">
<%= f.text_field :street, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :building, 'Building' %>
</div>
<div class="col-md-4">
<%= f.text_field :building, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :name, 'Place name' %>
</div>
<div class="col-md-4">
<%= f.text_field :name, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :phones, 'Phone' %>
</div>
<div class="col-md-4">
<%= f.fields_for :phone do |phone_form| %>
<%= phone_form.text_field :number, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= phone_form.label :extension, 'Ext.' %>
</div>
<div class="col-md-4">
<%= phone_form.text_field :extension, class: 'form-control' %>
</div>
<% end %>
</div>
<div class="form-group">
<div class='col-md-offset-4 col-md-6'>
<%= f.submit #address.new_record? ? 'Add' : 'Update', class: 'btn btn-primary btn-md' %>
</div>
</div>
</div>
<% end %>
</div>
</div>
First issue I encountered with is if I set key :phones instead :phone into the following line <%= f.fields_for :phone do |phone_form| %> my phone text fields don't render in view but they should. One user emphasized this moment here https://stackoverflow.com/a/3328041/2049476
if I use :phone everything somehow works fine but seems like it's wrong.
And the second one.
Phone object doesn't save in DB, when I create new address or edit current I succeed but phone doesn't show any validation errors if I leave all it fields blank.
Here what I have in params hash
{"utf8"=>"✓",
"authenticity_token"=>"inwXr3Ev/Aj/hZRY2IadizDHDgdSFo2zFhY9DAvysfFu3jjD9AS66esKVsTzEuKo2WC46YQt6HnOKTgInvfUEg==",
"address"=>{"city"=>"Moscow", "street"=>"ul. Tsentralnaya d. 4 kv. 220", "building"=>"1212", "name"=>"Astoria", "phone"=>{"number"=>"9215555555", "extension"=>"111"}},
"commit"=>"Add",
"controller"=>"addresses",
"action"=>"create"}
What am I missing?
Try answer for 2 issues:
The correct way is to pass :phones, and then phone as variable to field_for, like is was done here:
<%- #address.phones.each.with_index do |phone, index| %>
<%- f.fields_for :phones, phone do |phone_form| %>
<%- end %>
<%- end %>
Should be resolved as of the 1-st question, since the fields shoudl sent ot server via params not a phone hash, but phones_attributes array of hashes, in order to accepts_nested_attributes_for could accept phones:
phones_attributes: [{ ... },{ ... }]

Save relation with omniauth identity

I would like to let the user choose the service (free, standard, pro) in the registration step.
Here is the db model i'm working with:
(User)1---n(Subscription)n--1(Service)
In the "new user" form I have this customised code in order to let the user chose the service:
identities/new.hmtl.erb
<%= form_tag "/auth/identity/register", :html => {:role=>"form"} do %>
<div class="form-group">
<label>Service</label>
<%= select("service", "service_id", #available_services, {:selected => params[:service_id]}, {class:"form-control"}) %>
</div>
<div class="form-group">
<label>Name</label>
<%= text_field_tag :name, nil, class:"form-control" %>
<p class="help-block">Nome e cognome completo e corretto.</p>
</div>
<div class="form-group">
<label>Email</label>
<%= text_field_tag :email, #identity.try(:email), class:"form-control" %>
</div>
<div class="form-group">
<label>Password</label>
<%= password_field_tag :password, nil, class:"form-control"%>
</div>
<div class="form-group">
<label>Password confirmation</label>
<%= password_field_tag :password_confirmation, nil, class:"form-control"%>
</div>
<%= submit_tag "Sign up",class:"btn btn-default" %>
<% end %>
identities_controller.rb
class IdentitiesController < ApplicationController
skip_before_filter :require_login
layout "static"
def new
#available_services = Service.all.where(:id => [1, 2, 3]).collect {|p| [ p.name, p.id ] }
#identity = env['omniauth.identity']
end
end
Now, what's the way to create/save the user and the relation between the new user and the selected subscription?
I solved this by...
Adding an hidden field for the service:
#identitiy.new.html
<%= hidden_field_tag :service_id, params[:service_id] %>
Edited the omniauth initializer as follow:
#omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :identity,:fields => [:service_id,:name,:email], on_failed_registration: lambda { |env|
IdentitiesController.action(:new).call(env)
}
end
Added attr_accessor and a after_create method in the Identity model:
#identity.rb
class Identity < OmniAuth::Identity::Models::ActiveRecord
attr_accessor :service_id
validates_presence_of :name
validates_uniqueness_of :email
#validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
after_create :add_subscription
private
def add_subscription
Subscription.create(:user_id => self.id, :service_id => service_id.to_f)
end
end

Resources