user3785435
user3785435

Reputation:

Custom fields in form_for

Trying to create a profile form in which a user can add information about their hobbies to their user profile. But I get the following error when trying to do so.

    NoMethodError in Users#edit_profile

    undefined method `hobbies' for #<User:0x007ff1a8a1f198>

Does anyone know what the problem could be, or a potential solution? I'm new to rails but I was under the impression that 'text_field' was a safe bet to make any custom input work. Would installing the strong parameters gem help this out at all?

edit_profile.html.erb

<h2>Tell us about yourself</h2>

<%= form_for @user do |f| %>

    <%= f.label :first_name %><br />
    <%= f.text_field :first_name, autofocus: true %>

    <%= f.label :last_name %><br />
    <%= f.text_field :last_name %>

    <%= f.label :hobbies %><br />
    <%= f.text_field :hobbies %>

  <div><%= f.submit "Update" %></div>
<% end %>

user_controller.rb

class UsersController < ApplicationController
  before_filter :authenticate_user!
    def index
      @users = User.all
    end

    def show
      @user = User.find(params[:id])
    end

    def new
      @user = User.new
    end

    def create
    end

    def edit
    end

    def update
      @user = User.find(params[:id])
      @user.update!(user_params)
      redirect_to @user
    end

    def destroy
    end

    def edit_profile
      @user = User.find(params[:id])
    end

    def user_params
      params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :hobbies)
    end

end

user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :remember_me, :hobbies

  #validates :first_name, presence: true, length: { maximum: 50 }
  #validates :last_name, presence: true, length: { maximum: 50 }

end

Upvotes: 0

Views: 1361

Answers (2)

Richard Peck
Richard Peck

Reputation: 76774

Does anyone know what the problem could be, or a potential solution?

Sure - the problem is you don't have a hobbies attribute in your User model :)

Since you're new, I'll explain a bit about Rails after I answer the question. However, let me explain the value of creating the right attributes:

#app/models/user.rb
class User < ActiveRecord::Base
   attr_accessor :hobbies
end

This is what you'll need to create a single attribute for your User model. The attr_accessor directive is a Ruby method which sets a getter and setter in your User model

This will give Rails the ability to populate the hobbies attribute of your Model. However, the data will not be persistent, as it will only be set on a per-instance basis in the model, meaning it will be lost when you refresh the page etc

Using the code above should get your form working, regardless of whether you're using Rails 3 or 4.


Models

Rails is famously an MVC framework - which means it has 3 core components - models (builds data from the database), controllers (configure data for the view) & views (displays the data from the controller & model).

When you load a Rails application, you're sending a request, which will be routes to a particular controller action. This will then call data from your database, allowing you to manipulate it in your view.

Models, therefore have to be populated from your database. They do this by taking the various attributes you have in your datatables, and creating a series of getters and setters for them. These give you the ability to access the data within the attributes, or set new ones.

Your error occurs because you don't have the relevant attribute set in your datatable. You'll need to create a migration to add the hobbies attribute to your User model:

> $ rails g migration AddHobbiesToUser hobbies:string
> $ rake db:migrate

The migration should create something like:

class AddPartNumberToProducts < ActiveRecord::Migration
  def change
    add_column :users, :hobbies, :string
  end
end

Upvotes: 0

Paulo Fidalgo
Paulo Fidalgo

Reputation: 22296

You don't mention it, but I will assume you're running Rails 4.x.

Rails 4.x introduced strong parameters, so in your controller you need to add a private method to set the allowed parameters and remove the attr_accessible from your model.

So in you case it will be:

 def user_params
    params.require(:first_name, :last_name).permit(:email, :password, :password_confirmation, :remember_me, :hobbies)
  end

If you still have trouble to understand the concept, or came from a previous Rails version, take a look at this blog post.

Upvotes: 2

Related Questions