When I use delete method to update a has_many relationship in a model on Hyperstack, the association is not updated in the database, and the association is deleted only on the front end side.
I have installed rails-hyperstack gem 'edge' branch, on rails 5.1.7
In Main component in this code, Agent#deassign(number) is called when clicking the number in the page.
I am trying to use delete method in Agent#deassign(number) method in this code to delete the association with an issue.
app\hyperstack\components\main.rb
class Main < HyperComponent
before_mount do
@current_agent = Agent.first
end
render(UL) do
@current_agent.issues.pluck(:number).each do |num|
LI do
num.to_s
end
.on(:click) do
@current_agent.deassign(num)
end
end
end
end
app\hyperstack\models\issue.rb
class Issue < ApplicationRecord
belongs_to :agent
end
app\hyperstack\models\agent.rb
class Agent < ApplicationRecord
has_many :issues
def deassign(number)
issue_to_deassign = issues.detect { |issue| issue.number == number }
issues.delete(issue_to_deassign)
end
end
app\db\schema.rb
...
create_table "agents", force: :cascade do |t|
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
...
create_table "issues", force: :cascade do |t|
t.integer "number"
t.integer "agent_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["agent_id"], name: "index_issues_on_agent_id"
end
The issue is deleted from the agent.issues array on the front end, and the number disappears from the page as expected.
But the association isn't updated in the database unexpectedly, and the number re-appears when I reload the page.
Unlike the normal serverside ActiveRecord API you need to explicitly save the item that was removed
issues.delete(issues_to_deassign).save
WHY?
The problem is that deleting an item implies a database save will occur.
Because the browser must be asynchronous with the server, Hyperstack returns a promise for any AR methods that update the database (i.e. save, update, create, etc.) The promise will then resolve when the database update completes.
However the expectation is that thedelete
method returns the object that was just deleted, thus we have a contradiction.
So there was 3 design choices.
1. Break how delete works, and do the save and return a promise;
2. Have delete do the save, but instead of a promise return the deleted item;
3. Have delete return the item, and let the developer do the save explicitly.
Options 1 and 2, are not good since the make the delete operation inflexible.
Option 3, while breaking the standard semantics of ActiveRecord allows those semantics to be easily implemented if desired (i.e. by addingsave
to the end) without sacrificing flexibility