1

I have User model (for devise ) and then i have member which references User and then portfolio which references member .

i have created a user while signingup . Now i want the signed up user to update his deatails which is members and portfolio tables . The portfolio model is :-

class Portfolio < ApplicationRecord
  belongs_to :member
  validates_presence_of title:
end

class Member < ApplicationRecord
  belongs_to :user
  has_one :portfolio
  accepts_nested_attributes_for :portfolio
end

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

  validates_presence_of :name 
  validates :email, uniqueness: true  
  after_create :create_member_portfolio

  def create_member_portfolio
    puts "Test "
  end  
end 

in my members_controller the code i have is :-

class MembersController < ApplicationController
  before_action :set_member, only: [:show, :edit, :update, :destroy]

  # GET /members
  # GET /members.json
  def index
    @members = Member.all
  end

  # GET /members/1
  # GET /members/1.json
  def show
  end

  # GET /members/new
  def new
    @member = setup_member(Member.new) 
  end

  # GET /members/1/edit
  def edit
  end

  # POST /members
  # POST /members.json
  def create
    p = member_params
    byebug
    @member = Member.new(p)
    byebug
    @member.user_id =  current_user.id unless current_user.nil?

    respond_to do |format|
      if @member.save
        format.html { redirect_to @member, notice: 'Member was successfully created.' }
        format.json { render :show, status: :created, location: @member }
      else
        format.html { render :new }
        format.json { render json: @member.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /members/1
  # PATCH/PUT /members/1.json
  def update
    respond_to do |format|
      if @member.update(member_params)
        format.html { redirect_to @member, notice: 'Member was successfully updated.' }
        format.json { render :show, status: :ok, location: @member }
      else
        format.html { render :edit }
        format.json { render json: @member.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /members/1
  # DELETE /members/1.json
  def destroy
    @member.destroy
    respond_to do |format|
      format.html { redirect_to members_url, notice: 'Member was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_member
    @member = Member.find(params[:id])
  end

  def setup_member(member)
    member.portfolio ||= Portfolio.new
    member
  end

  # Only allow a list of trusted parameters through.
  def member_params
    # slice(*filter.keys).each{|k,v| puts "#{k}:#{v}"}
    #byebug
    params.require(:member).permit(
                                   :dob,
                                   :email,                                   
                                   :phone,                                   
                                   portfolio_attributes: [ :title, :subtitle ]
                                   )
  end
end

And the html.erb is as given below :-

<%= form_for(@member) do |f| %>
  <% if @member.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(member.errors.count, "error") %> prohibited this member from being saved:</h2>
      <ul>
        <% @member.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <div class="form-control">
    <%= f.label :dob %>
    <%= f.datetime_select :dob %>
  </div>
  <div class="form-control">
    <%= f.label :email %>
    <%= f.text_field :email %>
  </div>

  <div class="form-control">
    <%= f.label :phone %>
    <%= f.text_field :phone %>
  </div>
  <div class="col-md-12">
    <h2>Profile Details :</h2>
    <div>
      <%= f.fields_for :portfolio do |ff| %>
        <div class="form-control">
          <%= ff.label :title %>
          <%= ff.text_field :title %>
        </div>
        <div class="form-control">
          <%= ff.label :subtitle %>
          <%= ff.text_field :subtitle %>
        </div>
      <% end %>
    </div>
  </div>
  <div class="form-group">
    <%= f.submit 'Save Member Item', class: 'btn btn-primary btn-block' %>
  </div>
<% end %>

But when in the create controller method on save of member object it fails and says that Portfolio.member does not exist . Although i an getting the portfolio_attributes as key with title and subtitle in the passed in params and those are validated too , but fails on save . Could you please let me know what did i do wrong here ?

The error i am gettng here adter member.save is called is as shown below :-

byebug) @member.errors
#<ActiveModel::Errors:0x00007fa011bceba8 @base=#<Member id: nil, fname: "asdsa", lname: "asdfsda", dob: "2020-06-16 18:59:00", email: "asddfsda@asdfdsa.com", religion_id: nil, phone: "", created_at: nil, updated_at: nil, user_id: 1>, @messages={:"portfolio.member"=>["must exist"]}, @details={:"portfolio.member"=>[{:error=>:blank}]}>
(byebug) 
  • This is what i recieve in the response params : "asdsa", "lname"=>"asdfsda", "dob(1i)"=>"2020", "dob(2i)"=>"6", "dob(3i)"=>"16", "dob(4i)"=>"18", "dob(5i)"=>"59", "email"=>"asddfsda@asdfdsa.com", "country_id"=>"", "phone"=>"", "portfolio_attributes"=>"adsfds", "subtitle"=>"asdfs"} permitted: true>} permitted: true> – user2742176 Jun 16 '20 at 19:01

2 Answers2

0

You might be able to isolate which field is causing the error by checking:

@member = Member.new(p)
@member.valid?
@member.errors

For more information, see the valid? and invalid? section of the Active Record Validations and Callbacks documentation.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • This is what i am recieving in the response : – user2742176 Jun 16 '20 at 19:00
  • **The @member.valid? is false and the member.errors gives following results on save :- ** (byebug) @member.errors #, @messages={:"portfolio.member"=>["must exist"]}, @details={:"portfolio.member"=>[{:error=>:blank}]}> (byebug) @member.valid? false – user2742176 Jun 16 '20 at 19:09
0

It seems there is a bug in version rails 5.0 . and to move away from the default behavior(not allowing to save entry without the parent entry ) we'll have to add

class Portfolio < ApplicationRecord
  belongs_to :member, optional: true
end

which should do the trick . To follow check this link :-

https://github.com/rails/rails/issues/18233