3

This is for Rails 4.04 and Ruby 2.1. I'd like to allow my users to have addresses. So I generated an address table and gave it columns (NUMBER, STREET, CITY, STATE). Now when I go to the following url, I'd like to be able edit this information:

webapp.com/users/edit/

However I noticed it only showed the same old information (name, password, email). So I went to the view and added simple_fields for my new relationship so the view now looks like this:

<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
 <div class="form-inputs">
    <%= f.input :email, required: true, autofocus: true %>
    <%= f.input :name, required: false %>
    <%= f.simple_fields_for :addresses do |a| %>
        <%= a.input :number %>
        <%= a.input :street %>
        <%= a.input :city %>
        <%= a.input :state %>
        <%= a.input :country %>
  <% end %>
<%end%>

However it still doesn't generate the fields needed for address. I think this is because none of my users currently have any addresses attached to their account profile (because this migration was just created). However, in this case there should be blank fields generated so I can ADD address information.

I feel like I need to do something in the Users#Edit action like this

@users.each do |user|
        user.address.build
    end

Is that right? How can I override the users controller because this was created by Devise and I don't actually have a users controller (I looked for it it and couldn't find it).

UPDATE

Ok, I'm getting closer. I had to create my own controller to override Devise's default registrations controller as explained in the second answer of this stack overflow article:

Override devise registrations controller

So now I am getting into that controller which currently looks like this:

class Users::RegistrationsController < Devise::RegistrationsController
  def edit
    super
  end
end

However, when I get to my view, it's still SKIPPING the block that starts like this:

<%= f.simple_fields_for :addresses do |a| %>

However, if I go manually into my DB and add a record in the addresses table and link it to my currently_signed in user via the foreign key, then the block does not get skipped. So whats the best way to generate this connection if the address record does not yet exist? Is it the build method? e.g.

user.address.build 

in the controller

SOLUTION

Yes, I needed to added this method to my new registrations_controller.rb file

def edit
    if resource.addresses.size == 0
      resource.addresses.build
    end
    super
  end

It is now working the way I intended it.

Community
  • 1
  • 1
asolberg
  • 6,638
  • 9
  • 33
  • 46
  • devise doesn't come with a controller. i think there is a way of manually adding it. devise comes with `user model` and `users table` did you make the association of `users` and `addresses`? – Wally Ali May 25 '14 at 05:42

2 Answers2

0

it looks like you didn't made the relation between those models add to addresses column called user_id and add to user model:

has_many :addresses

and into addresses:

belongs_to :users

then in your view you can build this form using nested attributes see this post:

Rails 4 Nested Attributes Unpermitted Parameters

another option that you can do is to show that addresses form after the user already signed in then when he update the form find the user_id with current_user and build the record using this id but using strong params in Rails 4 is recommended to solve your issue.

Community
  • 1
  • 1
matanco
  • 2,096
  • 1
  • 13
  • 20
0

You need to do it like this:

#app/models/user.rb
Class User < ActiveRecord::Base
   has_one :address
   before_create :build_address, unless: Proc {|x| x.address.present? } #-> not sure about the if statement
end

#app/models/address.rb
Class Address < ActiveRecord::Base
   belongs_to :user
end

--

Devise does come with Controllers

These controllers are not shown in your app (they are installed with the Devise gem, but only visible in production):

- confirmations_controller.rb
- omniauth_callbacks_controller.rb
- passwords_controller.rb
- registrations_controller.rb
- sessions_controller.rb
- unlocks_controller.rb

--

You Don't Need Them

Whilst you can override these controllers, you won't need to, as your edit action will be tied to the users controller:

#config/routes.rb
resources :users

#app/controllers/users_controller.rb
Class UsersController < ApplicationController
   def edit
      @user = User.find params[:id]
   end
end

#app/views/users/edit.html.erb
<%= form_for @user do |f| %>
   ...
   <%= f.fields_for :address do |a| %>
   <% end %>
<% end %>

Update

Sorry for not explaining. You can use resources :users with devise_for :users:

#config/routes.rb
devise_for :users
resources :users, only: [:edit, :update]

If this does not work, you may need to change the path_names argument for devise, like so:

#config/routes.rb
devise_for :users, path_names: { sign_in: 'login', password: 'forgot', confirmation: 'confirm', unlock: 'unblock', sign_up: 'register', sign_out: 'logout'}

-

Form

The form can have resource, but I think you need to work out what you're trying to change. If you're trying to change a devise object, then use the resource helper; but if you're trying to change the User model directly - I'd be partial to changing that!

The issue I think you have is if you're using resource, it's going to route to Devise controller actions. I would try setting @user in the edit action of your users controller, and use the conventional way to update

Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Question #1 is you said Class UsersController < ActiveRecord::Base but seems like it should be Class UsersController < ApplicationController. #2 is that the users_controller.rb file didn't exist in my app, I had to create it. #3 is in my routes file I have the line "devise_for :users" and you didn't mention if that should be left in or not in addition to "resources :users" #4 is that in my view I don't have form_for @user.... I have "simple_form_for(resource, as: resource_name,", and #5 is the actual error I'm now getting which is "The action 'show' could not be found for UsersController" – asolberg May 25 '14 at 13:40
  • I traced the action back and I can see that its going through a special devise controller in the Gem (class Devise::RegistrationsController < DeviseController). This is the controller that gets used when I go to webapp.com/users/edit/ – asolberg May 25 '14 at 13:47
  • Updating my original post – asolberg May 25 '14 at 15:57
  • 1
    I didn't quite use the approach you recommended but Im going to select your answer because it was the most thorough and much of it is relevant the the correct answer. – asolberg May 25 '14 at 16:25