I am building a job board and therefore have two user models and employer and an applicant.
I am using devise and therefore my challenge now is to use this with the polymorphic relationship.
Through some rails console testing I know that (resource) in devise passes all the user information and it is passing the role_type which is either applicant or employer. However it is set to nil and therefore although my user is being saved it is not saving the role type of applicant or employer. Furthermore nothing is being saved in the applicant or employer tables just in the user table. My code is below but my question really is how do I pass the role_type to the devise resource hash? Or if this isnt possible the most elegant way of solving this problem.
Many Thanks!
Also the full project code is here if I have missed anything https://github.com/PatGW/jobs
Below is the views->devise->user->new.html.erb
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2> Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</p>
<p>
<%= radio_button_tag :role_type, "employer", :checked => false %><br />
<%= label :role_type, 'Employer' %>
</p>
<p>
<%= radio_button_tag :role_type, "applicant", :checked => true %><br />
<%= label :role_type, 'Applicant' %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
UsersController which inherits from DeviseController
class UsersController < Devise::RegistrationsController
def new
super
end
def create
User.transaction do
super
after_sign_in_path(resource)
end
end
private
def after_sign_in_path(resource)
debugger
#user = User.new(params[:user])
if params[:role_type] == "coach"
role = Employer.create
else params[:role_type] == "player"
role = Applicant.create
end
end
end
The problem here is not Devise related, but association / OO related. I checked out your code: Your applicant and employer model seem to HAVE a user field, while those models should actually inherit from user, for they ARE a kind of user. So, try this:
class Employer < User
attr_accessible :location, :logo, :name
end
for starters, and see if it helps. (Btw: Obviously, you should also change the code for applicant)
Related
We have two models, a 'Devise User' and an 'Influencer'. An Influencer is a User, as such it must have a User (from the db standpoint). A User can be multiple other things. Thus, we want to have the ability to sign up a User without being an Influencer and we want to sign up a User when they want to sign up as an Influencer.
I have a form like so:
influencers/new.html.erb
<%= form_for #influencer do |i| %>
<%= i.fields_for(resource, as: resource_name, url: registration_path(resource_name)) do |u| %>
<div id="registration_fields">
<%= render 'devise/registrations/registration_fields', f: u %>
</div>
<% end %>
<div class='field'>
<%= i.label :twitter_handle %><br/>
<%= i.text_field :twitter_handle %>
</div>
<div class='field'>
<%= i.label :short_bio %><br/>
<%= i.text_area :short_bio %>
</div>
/views/devise/registrations/_registration_fields
<%= devise_error_messages! %>
<div class="field">
<%= f.label :first_name %> <br />
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %> <br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
We've modified the ApplicationHelper and 'new' method so that it could render this Devise form without problems. Unfortunately, we are stuck as to how to properly make the 'create' method for our InfluencersController.
This is the hash we receive:
Parameters: {..., "influencer"=>{"user"=>{"first_name"=>"buddy", "last_name"=>"king", "email"=>"bdking#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "twitter_handle"=>"#bdking", "short_bio"=>"None"}, "commit"=>"Join as influencer"
Essentially we want to Devise to handle the user information while we handle the influencer information. We have tried calling the Devise::RegistrationsController.new.create method from within InfluencersController#create. However, this poses its own difficulties (even with multiple hacks we reach different problems such as, missing '#response' or missing 'response.env' or missing 'devise.mappings').
With that said, We believe that inheriting will allow us to call 'super' in the create function. However, we do not want to have InfluencersController inherit from Devise::RegistrationsController since this controller is not by any means a true Devise controller.
Is there any way we could get around this?
I would use the tried and true pattern of users and roles.
Basically your User class is in charge of authentication (identity) and the user has many Roles which can be used for authorization (permissions).
class User < ActiveRecord::Base
has_many :roles
def has_role?(role)
roles.where(name: role)
end
end
class Role < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :name, scope: :user_id
end
So an "influencer" is really just a user with a Role(name: "influencer") attached to it. The real power and flexibility is that it makes it trivial to implement granting/revoking roles from a web GUI.
And you don't have to mess around with how Devise/Warden handle authentication to support multiple classes which can get really messy.
Best part is that the Rolify gem makes it really trivial to set up.
If you need to setup a specific endpoint (influences/registrations) to register "influencers" you can simply override the build_resource method in the Devise controller:
class InfluencerRegistrationsController < Devise::RegistrationsController
def resource_class
User
end
def build_resource
super
self.resource.roles.new(name: :influencer)
end
end
I am new to ruby with rails,I generated a new Controller named users by using command:
rails generate controller users register index login
After that I opened register.html.erb and wrote following code:
<h1>Register New User</h1>
<p>
<%= form_for :user do |f| %>
<%= f.label:USERID %><%= f.text_field:userid %><br />
<%= f.label:PASSWORD %><%= f.text_field:password %><br />
<%= f.label:EMAIL %><%= f.text_field:email %><br />
<br />
<%= f.submit %>
<% end %>
</p>
Then in users_controller.rb I wrote following code in register:
class UsersController < ApplicationController
def index
end
def show
end
def login
end
def register
print "test"
end
def user_params
params.require(:user).permit(:userid,:password,:email)
end
end
And test is not being printed and get and post methods of the form are not working at all.
And params.require(:user).permit(:userid,:password,:email) is not working as well. I get error that :user is empty.
I get error that :user is empty.
form_for(path/to/your/controller/action) is a helper method to create HTML form elements with the url path to the POST or GET request. The helper knows if it should be a new record or an update record based on what you are asking to do in your controller action. So, basically, it's looking for the #user in the corresponding controller action when you write form_for #user in your view. As you don't have it currently, hence you ar getting this error.
See this for more information.
To solve your current problem, you have to define the #user in the controller's register action:
def register
#user = User.new(user_params)
end
Then, in your register.html.erb file's form, you can use that #user:
<h1>Register New User</h1>
<p>
<%= form_for #user do |f| %>
<%= f.label :USERID %>
<%= f.text_field :userid %><br />
<%= f.label :PASSWORD %>
<%= f.text_field :password %><br />
<%= f.label :EMAIL %>
<%= f.text_field :email %><br />
<br />
<%= f.submit %>
<% end %>
</p>
Let's say I have 2 models, Box.rb and Toy.rb. Rails gives me pages and methods to create new toys and boxes independently. However, I would like to ensure/provide the ability to create a box's first toy when creating a box for the first time.
In line with DRY, I wanted to simply put <%= render "Toy/form" %> inside the _form.html.erb file that is made for Box.
The problem is that Toy's _form file contains, well, a form_for method for obvious reasons. It's a problem for what I am trying to do because I will end up with 1 form nested in the other, while all I really want is to get the Toy fields while keeping to DRY…?
You should be using accepts_nested_attributes_for along with fields_for.Assuming your associations are like this
#box.rb
Class Box < ActiveRecord::Base
has_many :toys
accepts_nested_attributes_for :toys
end
#toy.rb
Class Toy < ActiveRecord::Base
belongs_to :box
end
#box_controller.rb
def new
#box = Box.new
#toy = #box.toys.build
end
def create
#box = Box.new(box_params)
if #box.save
-----
else
-----
end
end
private
def box_params
params.require(:box).permit(:box_attribute_1,:box_attribute_2,:more_box_attributes, toys_attributes: [:toy_attribute_1,:more_toy_attributes])
end
In your box/form,you can do like this
<%= form_for(#box) do |f| %>
<div class="field">
<%= f.label :box_attribute_1 %><br />
<%= f.text_field :box_attribute_1 %>
</div>
<div class="field">
<%= f.label :box_attribute_2 %><br />
<%= f.text_field :box_attribute_2 %>
</div>
<div class="field">
<%= f.label :box_attribute_3 %><br />
<%= f.text_field :box_attribute_3 %>
</div>
<%= f.fields_for #toy do |builder| %>
<%= render 'toys/form', :f => builder %>
<% end %>
<% end %>
I am trying to have a form show up for a related model, but it is not displaying when I view the page in a browser. How do I url field in my fields_for to display?
Here is my code:
User Model:
class UsersController < ApplicationController
def new
#user = User.new
#user.websites.build
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
end
Website Model:
class Website < ActiveRecord::Base
belongs_to :user
end
Users View:
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
...
<% end %>
<p>
<%= f.label :email %><br/>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br/>
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %><br/>
<%= f.password_field :password_confirmation %>
</p>
<% f.fields_for :websites do |builder| %>
<%= builder.label :url %><br/>
<%= builder.text_field :url %>
<% end %>
<p class="button"><%= f.submit %></p>
<% end %>
Final output:
You missed the equals sign in your erb tag.
<% f.fields_for :websites do |builder| %>
.. should be ..
<%= f.fields_for :websites do |builder| %>
Does that fix it?
It looks like you're maybe confusing singular and plural in your fields_for as well. Calling it with the plural websites then treating the block as a singular website doesn't make sense.
I have the following form:
<% form_for(#account, :url => admin_accounts_path) do |f| %>
<%= f.error_messages %>
<%= render :partial => 'form', :locals => {:f => f} %>
<h2>Account Details</h2>
<% f.fields_for :customer do |customer_fields| %>
<p>
<%= customer_fields.label :company %><br />
<%= customer_fields.text_field :company %>
</p>
<p>
<%= customer_fields.label :first_name %><br />
<%= customer_fields.text_field :first_name %>
</p>
<p>
<%= customer_fields.label :last_name %><br />
<%= customer_fields.text_field :last_name %>
</p>
<p>
<%= customer_fields.label :phone %><br />
<%= customer_fields.text_field :phone %>
</p>
<% end %>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
As well as
attr_accessor :customer
And I have a before_create method for the account model which does not store the customer_fields, but instead uses them to submit data to an API.. The only thing I store are in the form partial..
The problem I'm running into is that when a validation error gets thrown, the page renders the new action (expected) but none of the non-column attributes within the Account Detail form will show?
Any ideas as to how I can change this code around a bit to make this work me??
This same solution may be the help I need for the edit form, I have a getter for the data which it asks the API for, but without place a :value => "asdf" within each text box, it doesn't populate the fields either..
Okay, what you need to do is create a class to handle your customer with and without a Braintree gateway connection. First, create the class:
class Customer
attr_accessor :company, :first_name, :last_name, :phone, :gateway
def initialize gateway_id=nil
begin
#gateway = Braintree::Customer.find(gateway_id) unless gateway_id.nil?
rescue Braintree::NotFoundError
end
end
def company
#gateway.nil? ? #company : #gateway.company
end
# Implement the rest of the methods this way as well. You can even use
# meta-programming so that you don't repeat yourself.
end
You'll notice that calling Customer.new(id).company will work with and without an id or gateway, because if a gateway non-existent #company will be returned, and if a gateway is present the gateway's company will be returned.
Finally, hook this into your model:
class Account
def customer
#customer ||= Customer.new(self.gateway_customer_id)
end
def customer= h
#customer = Customer.new
#customer.company = h[:company]
...
#customer
end
end
You'll have to modify how you write code to the API so that you use customer.company instead of customer[:company] for example, but you can probably write a function within the Customer class to do this easily.
You'll have to modify your form to:
<% f.fields_for :customer, #account.customer do |customer_fields| %>