Adding multiple emails to the user model - ruby-on-rails-3

I want to add multiple emails to the user model while using devise, using a has_many relationship. It's a bit of an extension to this question: How can I configure Devise for Ruby on Rails to store the emails and passwords somewhere other than in the user model?
User.rb
has_many :emails
Email.rb
belongs_to :user
In my new/edit form for devise how do I set up the fields_for xxx.email. I can see that the registration page from devise uses "resource". When I try the following code it just skips the email field.
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
= devise_error_messages!
%table{:style=>"width:400px;"}
-fields_for resource.email do |emails|
%tr
%td
= emails.label :email
%td
= emails.email_field :email
%tr
%td
= f.label :password ...
%tr
%td
= f.label :firstname ....
Also, who do you modify the actions in the controller for devise?
In this case, the entire email block does not apear.
Thanks

The helper fields_for need some data to create the fields. With new records, usually is needed you do something like resource.emails.build to create a first record to be showed.
And also, I think you should use fields_for(resource.emails) do |email|.

Related

Rails form_for action has a corrupted locale

I have an account dashboard that lists the offices and for each office the jobs available.
Hierarchy:
Companies (1 user has 1 company, I access if from the user profile)
Offices (each company can have multiple offices)
Jobs (each office can have multiple jobs)
Models:
class Company < ActiveRecord::Base
has_many :offices, :dependent => :destroy
has_many :jobs, :through => :offices
class Office < ActiveRecord::Base
belongs_to :company
has_many :jobs, :dependent => :destroy
class Job < ActiveRecord::Base
belongs_to :office
For each job I have an edit link
E.g. for job id 10 (job is a local variable from iteration on office jobs)
= link_to edit_job_path(I18n.locale, job)
-> localhost:3000/de/jobs/10/edit
When I click on the edit link, I go to the edit page. So far so good, but the form looks like that:
<form accept-charset="UTF-8" action="/10/jobs/10" class="edit_job" enctype="multipart/form-data" id="edit_job_10" method="post">
Notice, that my locale (de in this example) disappeared and has the job id instead!
My routes.rb
scope "/:locale" do
resources :companies
resources :offices do
resources :jobs
end
resources :jobs
end
There are two jobs mentioned, I probably can do without but it's an easy way for me to either mention directly the job url to view or add office variable in the create new job link and use :office_id (in my dashboard controller: link_to new_office_job_path(I18n.locale, office) then in my form for new jobs: = f.hidden_field :office_id)
But even if I remove the resources :jobs in the :offices. The locale is still replaced by the job id in the edit form.
Note that I can edit the job properly, but because the locale is changed, the localisation text are all wrong after my redirect.
Any idea how to fix that?
------ Additional data requested -----------
= form_for(#job) do |f|
.field
= f.label :name, t(:job_title)
= f.text_field :name
.field
= f.label :url, t(:job_url)
= f.text_field :url
.field
= f.hidden_field :office_id
.field
= f.label :pdf, t(:job_upload_pdf)
= f.file_field :pdf
.field
= f.label :tag_list, t(:job_tags)
= f.text_field :tag_list
.actions
= f.submit "Submit", :class => "btn btn-primary"
------ Additional information -----------
BTW: this work around works, I get /de/jobs/10 but I'd like to understand why the locale gets corrupted if I use the default form_for.
= form_for #job, :url => job_path(I18n.locale, #job) do |f|
You can handle the locale using a Routing Filter, I've tried it in my project, you don't have to worry about locale in routes, the filter will handle it for you.
# in config/routes.rb
Rails.application.routes.draw do
filter :locale
end
I hope this will solve your problem.
The form_for line builds the path, when building the path you also need to specify the locale. To do this cleanly (without specifying the url explicitly, which is also possible), write it as follows:
= form_for [I18n.locale, #job] do |f|
and that should render the correct path.
As specified in the documentation it will use the array to build the correct path (this works for namespaced and nested routes, so I am guessing it will also work for your locale).
An alternative is to specify the path explicitly, using the :url option.
HTH.

mongoid save embedded documents

I'm trying to build up on the following tutorial from railscast:
http://railscasts.com/episodes/196-nested-model-form-part-1
I'm trying to make everything work with mongodb and mongoid.
the scenario is:
I want to creates events linked to a location. Each events (dance class) contains many lessons.
So I thought that an embedded relationship would be perfect.
Here are my models
model Lesson
class Lesson
include Mongoid::Document
include Mongoid::Slug
field :name, :type => String
embedded_in :event
slug :name
end
model Event
class Event
include Mongoid::Document
include Mongoid::Slug
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
field :name, :type => String
field :description, :type => String
field :date, :type => DateTime
validates_presence_of :name
has_one :venue
referenced_in :venue
embeds_many :lessons
slug :name
end
model Venue
class Venue
include Mongoid::Document
include Mongoid::Slug
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
field :name, :type => String
field :location, :type => String
validates_presence_of :name, :location
belongs_to :event
slug :name
end
event controller
def create
#event = Event.new(params[:event])
if #event.save
flash[:notice] = 'Event was successfully created.'
end
respond_with(#Event, :location => events_url)
end
def update
# #event = Event.find(params[:id])
#event = Event.find_by_slug(params[:id])
if #event.update_attributes(params[:event])
flash[:notice] = "Event was succesfully updated"
end
respond_with(#event)
end
Then I have my Event view where I can create events and link it to a Venue. But I'd like to be abe to create the lessons from the Event view/model.
so I used the fields_for to generate a field linked to the Lessons model.
= form_for #event do |f|
.field
= f.label :name
%br/
= f.text_field :name
.field
= f.label :description
%br/
= f.text_area :description
.field
= f.label :venue_id
%br/
= f.collection_select :venue_id, Venue.all, :id, :name
.field
= f.label :date
%br/
= f.datetime_select :date
%h3 Add a Class
= f.fields_for :lessons do |builder|
= render "lesson_fields", :f => builder
.actions
= f.submit 'Save'
When I create or edit a new event I get an error message:
undefined method `extract_id' for "test":String
But the request parameter message on the error page shows my lessons value in the Event document.
"lessons"=>{"name"=>"test name lesson"}
When I remove the fields_for line, everything works fine. But then i don't know how to save the value for the nested documents.
I have same problem with embeds_many, but when i try change to has_many. It works!. Maybe you can try too.
can you post the exact code you use to create the Event, including parameters?
which version of Mongoid and Rails are you using?
First thing I noticed is that the following parameter hash does not match your Lessons model:
"lessons"=>{"content"=>"test name lesson"} # this looks wrong
this should be:
"lessons"=>{"name" => "test name lesson"}
Looks like your lessons form has the wrong label for the text input field .. it should be :name , not :content
To dry things up, you might want to try if the 'nested_form' gem works for you:
after installing the gem, use the nested_form_for instead of form_for in your view.
Check here for a more detailed description:
How can I handle this type of multi level forms in rails
See:
https://github.com/ryanb/nested_form (it's also referenced in the RailsCast you mentioned)
You also might want to check this:
field_for and nested form with mongoid
The conclusion of this story is...
I removed everything related to mongoid_slug and it started to work.
I then put everything back as it was to try to find out how to make it work with mongoid_slug and it just worked, like out of the box.
:(
Please include the following code in model event.rb
**accepts_nested_attributes_for :lessons**
This will fix your problem

How do I set up to has_many/belongs_to assocations so that only one combination is allowed?

I have three tables, applicants, users and ratings. The basic idea is that each applicant gets assigned a rating by any number of users. This part I have working without any problems. However, if a user goes to edit their rating (which includes a score), the form adds a second rating. I need to change things so that each user can only assign one rating for a given applicant.
class Applicant < ActiveRecord::Base
has_many :ratings
accepts_nested_attributes_for :ratings, :allow_destroy => true
class User < ActiveRecord::Base
has_many :ratings
The rating table just contains an applicant_id, a user_id and a score.
class Rating < ActiveRecord::Base
belongs_to :user
belongs_to :applicant
validates_uniqueness_of :applicant_id, :scope => :user_id
The rating validation makes sure that a second rating is not accepted, but I need to change the associations (or the form) so that a second score option never appears.
My applicant form:
<%= f.fields_for :ratings do |builder| %>
<%= builder.collection_select :score, Rating::SCORES, :to_s, :humanize %>
<%= builder.hidden_field :user_id, :value => current_user.id %>
<%= builder.hidden_field :applicant_id, :value => #applicant.id %>
<% end %>
How do I specify (in the applicant model, I'd guess, since that's the form I'm editing) that the applicant_id, user_id combo in the ratings table has to be unique?
I ended up getting things working by doing the following.
In my applicant controller, I changed the edit method to:
def edit
#applicant = Applicant.find(params[:id])
#my_rating = Rating.where(:applicant_id => params[:id]).where(:user_id => current_user.id)
if #my_rating.empty?
#my_rating = #applicant.ratings.build
end
end
Since I can't make a scope using the current_user, I figured it would work here. Then, in the form, I changed the nested attribute fields to:
<%= f.fields_for :ratings, #my_rating do |builder| %>
<%= builder.collection_select :score, Rating::SCORES, :to_s, :humanize %>
<% if builder.object.user_id.nil?%>
<%= builder.hidden_field :user_id, :value => current_user.id %>
<% end %>
<% end %>
The other important bit is the uniqueness validation in the ratings model above. That made sure that each user could have only one rating per applicant.
This seems to work fine for me, but if anyone has suggestions on how to improve this, I'd love to hear them.

updating user record with devise that has_one relationship

Im using devise to handle my user authentication and in my user model Ive stated that each user has_one :role.
Im using another table to hold all my user roles/permissions and I was wondering how to update the role?
EDIT - here is my user model
has_one :role, :dependent => :destroy
accepts_nested_attributes_for :role, :allow_destroy => true
attr_accessible :stuff.... :role
My role model
belongs_to :user
Ive added this to my form:
<%= f.fields_for :role, Role.new do |r| %>
<li class="full_width">
<%= r.label "User type" %>
<%= r.select(:status, %w[member artist commercial],{:include_blank => false}) %>
</li>
<% end %>
but it never saves the role record, I guess its because the user model didnt have attr_accessible :role so I set that up and now when I try to save I get a AssociationTypeMismatch error
EDIT - added the accepts_attributes_for and now I dont get the error but the role record isnt saved. Console shows
WARNING: Can't mass-assign protected attributes: role_attributes
See http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html#method-i-attr_accessible. You have to declare
attr_accessible :role_attributes
From the code snippet that you have pasted, it's not clear where you are building the association between the new Role and the User. You may need to do something like #user.build_role(...) or #role.build_user(...) in order to associate the user and the role prior to saving.

Can't mass-assign protected attributes:

I have pulled out all my hair. No more left... :(
I am using Spree 0.3.4, within an extension I need to register some retailers up. so I direct them to a retailers form which has many custom fields which belong to a retailer model...
So I am trying to validate/submit all the fields from one form like so
myextension/app/views/user_registrations/new.html.erb
<%= form_for (:user, :url => registration_path(#user, :type => "retailer) do |f| %>
<%= f.fields_for :retailer do |r| %>
<%= r.text_field :name %>
<% end %>
<%= f.text_field :email %>
<% end %>
etc etc
class Retailer < ActiveRecord::Base
belongs_to :user
validates :name,
:presence => true
end
class User < ActiveRecord::Base
has_one :retailer
accepts_nested_attributes_for :retailer
attr_accessible :retailer_attributes
# theres a whole lot more spree and devise stuff here. not sure worth mentioning
end
I have also added the abilities in the cancan ability.rb
The problem is the retailer feilds never get validated and the data is never inserted into the database...
I created a blank app, and tried this process from scratch with some plain old scaffolding and it works fine.
any ideas??
In your application helper, do something like this(assuming your have Ruby 1.9.* for the tap functionality, otherwise checkout rails returning here):
def setup_user(user)
user.tap do |u|
u.build_retailer if u.retailer.nil?
end
end
then in your view change it to this:
<%= form_for (setup_user(#user), :url => registration_path(#user, :type => "retailer) do |f| %>
See if that works.