anonn023432
anonn023432

Reputation: 3120

Delete value from serialized Array in ActiveRecord model

I have a rails model set up as:

class Master < ActiveRecord::Base
  belongs_to :user
  has_many :submasters
  serialize :subdocs, Array
end

It has a serialized array of submaster_docs which stores the id of the connected subdocs and my model for Subdocs is:

class Subdocs < ActiveRecord::Base
  belongs_to :user
end

Now I have a rails method which deletes a subdoc when user clicks on the delete button.

While deleting the Subdocs entries I want to remove the id of the Subdocs from Master also so that it doesn't try to create an association between them even after deleting Subdocs

My database entry of Master looks as follows:

<ActiveRecord::Relation [#<Master id: 3, user_id: 1, name: "Being Batman", description: "Every man who has lotted here over the centuries, ...", subdocs: ["5"]>]> 

Database entry of subdoc:

<ActiveRecord::Relation [#<Subdoc id: 5, user_id: 1, name: "subdoc1.pdf">]> 

Over here for example if a user deletes the subdoc 5 then I want to remove that value from subdocs array of all Master's

My method for deleting the subdocs is as follows:

def destroy
  @masters = {}
  @subdoc = Subdoc.find(params[:id])
  @masters = current_user.user.masters

  # Tried these methods to delete the value.
  # @subdocs = @masters.select { |t| t.subdocs.to_a - [params[:id]] }
  # @subdocs = @masters.each { |t| t[:subdocs] - params[:id] }   

  @subdoc.destroy
  return render :status => 200, :json => { :success => true }    
end

But this throws me the error: No Implicit conversion of String into Array

How can I correct this? Thanks!

Upvotes: 0

Views: 1056

Answers (2)

LukeS
LukeS

Reputation: 481

While I agree with max and you should not use this architecture, assuming you keep it as is, you will need to delete the item from the array in master and save master.

def destroy
  @masters = {}
  @subdoc = Subdoc.find(params[:id])
  @masters = current_user.user.masters
  @masters.each do |master| 
    if master.subdocs.index(params[:id])
      master.subdocs.delete(params[:id])
      master.save!
    end
  end  

  @subdoc.destroy
  return render :status => 200, :json => { :success => true }    
end

Upvotes: 0

max
max

Reputation: 102433

You don't want to use an array here. Especially not a serialized array:

  • You have to scan a string to be able use the column in a query.
  • ActiveRecord associations are built to work with actual foreign key columns. So are relational databases.
  • You get no referential integrity.

So start by creating a migration rails g migration add_master_to_subdocs

class AddMasterToSubdocs < ActiveRecord::Migration[5.0]
  def change
    add_reference :subdocs, :master, foreign_key: true
    remove_column :subdocs, :user_id
  end
end

We are also removing the user_id column since it won't be needed:

class Master < ActiveRecord::Base
  belongs_to :user
  has_many :submasters
  has_many :subdocs
end

class Subdocs < ActiveRecord::Base
  belongs_to :master
  has_one :user, through: :master
end

Upvotes: 2

Related Questions