AlexMart
AlexMart

Reputation: 43

Allow users to edit their profile fields in rails 4

I have a new question.

What I want to do?

I've created the profile for each player, now I want to allow users to edit their profile.

Part of this profile takes the devise table, with a second table called profiles.

Devise: Captures username, password and email

Profiles: Captures Personal Information

Schema of Profiles

  create_table "profiles", force: :cascade do |t|
    t.text   "about"
    t.string "fb"
    t.string "skype"
    t.string "birthday"
    t.string "twitter"
    t.string "steam"
    t.string "gender"
    t.string "occupation"
    t.string "location"
    t.string "interest"
  end

My profile_controller.rb (Updated)

class ProfileController < ApplicationController
    def index
      @profile = Player.all
    end

    def show
        @profile = Player.find_by(nick: params[:nick])
    end

    def edit
        # use this to populate a form in your view
         @profile = Player.find_by(nick: params[:nick])
    end

    def update
       @profile = Player.find_by(nick: params[:nick])
    if @profile.update_attributes(profiles_params)
         redirect_to(:action => "show", :profile => @profile.nick)
    else
       render("index")
    end
      end

  private
    def profiles_params
      params.require(:profiles).permit(:about, :skype)
    end
end

Rake routes

profiles GET    /profiles(.:format)              profiles#index
         GET    /profiles/:nick/edit(.:format)   profiles#edit
         GET    /profiles/:nick(.:format)        profiles#show
         PATCH  /profiles/:nick(.:format)        profiles#update
         PUT    /profiles/:nick(.:format)        profiles#update

Routes.rb

  devise_for :players

  resources :profile, param: :nick
  resources :profiles, only: [:index, :show, :edit, :update], param: :nick

Notes:

  1. I have a profile controller
  2. I have these pages:
    • show.html.erb
    • index.html.erb

Now my question is:

*How should I make the edit page for each users profile, considering that each user edits their own profile?

Once a user edits a field, I want this to be reflected on the page show.html.erb. How can I achieve this?*

** show.html.erb **

<div id="myTabContent" class="tab-content">
  <div class="tab-pane fade active in" id="info">
     <p><div class="form-group">
        <label for="textArea" class="col-lg-2 control-label">About  <%= @profile.nick %></label>
     <div class="col-lg-10">
     <pre style="padding-bottom: 200px;"><%= @profiles.about %>(THIS IS THE ERROR)</pre>
    <span class="help-block">In Progress</span>
   </div>
  </div></p>
</div>

** edit.html.erb (Not _edit, because missing template)**

<strong>Testing About</strong>
            <%= form_for :profiles do |f| %>
            <%= f.label :about %>
            <%= f.text_field :about %>
            <div class="btn btn-primary">
                <a href="http://localhost:3000/profile/<%= @profile.nick %>">
                    <%= f.submit "Update Profile", :class => 'btn btn-primary' %></a>
                </div>
                <% end %>

                <% end %>
                <p>I am editing for</p> 
                <%= @profile.nick %>

Thanks in advance

Upvotes: 0

Views: 2237

Answers (1)

Allan W Smith
Allan W Smith

Reputation: 756

Show should be used to display a users profile, not edit it - this is the rails way.

I suggest you jump over and have a read on rails resourceful routing: http://guides.rubyonrails.org/routing.html - this covers routes and CRUD.

Consider you have your resource, :profiles - in your routes this can be declared as:

resources :profiles

This route will automatically create the desired routes for you - in this case we only seem to want index, show, edit and update therefore this can be declared:

resources :profiles, only: [:index, :show, :edit, :update]

We now have the following routes, i've commented what their purpose should be:

GET /profiles           #show all profiles
GET /profiles/:id       #show specific user profile
GET /profiles/:id/edit  #edit specific user profile
PATCH /profiles/:id     #update a specific profile 

Now that we have our routes lets look at this from a controller perspective - i'm jsut going to focus on edit/update as this is your question:

class ProfileController < ApplicationController
    def index
      #do something
    end

    def show
        # do something
    end

    def edit
        # use this to populate a form in your view
        @profile = get_profile  
    end

    def update
       @profile = get_profile
    if @profile.update_attributes(profile_params)
       #do something on success
    else
       # do something on fail
    end
  end

  private
    def profile_params
      params.require(:profile).permit(:about, :skype, etc)
    end


    def get_profile
      nick = params[:nick]
      if Player.where(username: nick).present?
        if Player.where(username: nick).count == 1
          Player.includes(:profile).find_by(username: nick).profile
        else
          raise "Error: Multiple profiles found"
        end
      else
        raise "Error: Profile cannot be found"
      end        
    end
end

You'll notice the 'profile_params' method, this is apart of rails strong paramaters and whitelists the attributes we can use for mass assignment. Read more: http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

Because our routes are set up as expected for our profile, our forms are super simple as rails can infer everything.

edit.html.erb

<%= form_for @profile do |f| %>
   <%= f.text_field :about %>
   ... etc
   <% f.submit %>  # this will submit to profile#update
<% end %>

Further reading on form_for: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for

Ofcourse you should also be adding authorisation to the controller methods but hopefully i've covered the basic premise for you.

EDIT1: In regards to your comment I've added a private method for locating your user profile by either username or id (tweak to suit). But like I said, go through the linked readings so you can get an understanding of routing.

EDIT2: SO taking into consideration your further comments and the routes you added to the question i've updated your get_profile method.

Upvotes: 4

Related Questions