STC-847 Include work package associated versions model#23841
Conversation
|
@opf/communicator how do you feel about merging a database change that has no impact on the application? How do you feel about merging this to dev vs developing the whole feature on a feature branch? |
+1 for merging on my part.
|
| # See COPYRIGHT and LICENSE files for more details. | ||
| #++ | ||
|
|
||
| class WorkPackageAssociatedVersion < ApplicationRecord |
There was a problem hiding this comment.
How about making this a tad lighter?
| class WorkPackageAssociatedVersion < ApplicationRecord | |
| class WorkPackageVersion < ApplicationRecord |
There was a problem hiding this comment.
Either that, or lean in the opposite direction and make the naming more descriptive -- since the table stores associations, not versions.
| class WorkPackageAssociatedVersion < ApplicationRecord | |
| class WorkPackageVersionAssociation < ApplicationRecord |
There was a problem hiding this comment.
Good point. I prefer WorkPackageVersion, so I'll check that option 👍
| has_many :work_package_associated_versions, dependent: :delete_all | ||
| has_many :work_packages_target_versions, | ||
| -> { where(work_package_associated_versions: { kind: "target" }) }, | ||
| through: :work_package_associated_versions, source: :work_package | ||
| has_many :work_packages_observed_in_versions, | ||
| -> { where(work_package_associated_versions: { kind: "observed_in" }) }, | ||
| through: :work_package_associated_versions, source: :work_package |
There was a problem hiding this comment.
These should be inverted, right? Something like:
| has_many :work_package_associated_versions, dependent: :delete_all | |
| has_many :work_packages_target_versions, | |
| -> { where(work_package_associated_versions: { kind: "target" }) }, | |
| through: :work_package_associated_versions, source: :work_package | |
| has_many :work_packages_observed_in_versions, | |
| -> { where(work_package_associated_versions: { kind: "observed_in" }) }, | |
| through: :work_package_associated_versions, source: :work_package | |
| has_many :associated_work_packages, dependent: :delete_all | |
| has_many :targeted_work_packages, | |
| -> { where(work_package_associated_versions: { kind: "target" }) }, | |
| through: :associated_work_packages, source: :work_package | |
| has_many :observed_in_work_packages, | |
| -> { where(work_package_associated_versions: { kind: "observed_in" }) }, | |
| through: :associated_work_packages, source: :work_package |
| belongs_to :work_package | ||
| belongs_to :version | ||
|
|
||
| validates :kind, presence: true, inclusion: { in: VERSION_KINDS } |
There was a problem hiding this comment.
Shall we throw in the uniqueness validation, since it's already there at the index level?
There was a problem hiding this comment.
You mean validating the combination of kind + version_id + work_package_id?
I think it is okay for clarity when looking at the model, but I assume rails will do slower shenanigans to validate such constraint (as opposed to the index validation directly on the DB). I don't think there's a lot of benefit of doing both
There was a problem hiding this comment.
In the end I did not include this one. If you feel strongly let me know and I'll check again.
| #++ | ||
|
|
||
| class WorkPackageAssociatedVersion < ApplicationRecord | ||
| VERSION_KINDS = %w[target observed_in].freeze |
There was a problem hiding this comment.
I'd consider a modern enum here. 👀
There was a problem hiding this comment.
It would mean changing the DB field to an integer. I don't feel too strongly about the options here. We get rails goodies at the expense of clarity on the DB itself.
There was a problem hiding this comment.
class WorkPackageVersion < ApplicationRecord
# VERSION_KINDS = %w[target observed_in].freeze
enum :kind, { target: 0, observed_in: 1 }, validate: true
belongs_to :work_package
belongs_to :version
# validates :kind, presence: true, inclusion: { in: VERSION_KINDS }
endThere was a problem hiding this comment.
I preferred enum, so switched to it. Thanks for the suggestion 🙇
There was a problem hiding this comment.
It would mean changing the DB field to an integer. I don't feel too strongly about the options here. We get rails goodies at the expense of clarity on the DB itself.
That's the neat part, the "modern" Postgres enums are also enums in the database! [related guide]
The usual downside is that adding a new enum value requires a DB migration -- but in this case, this is not likely to get touched very often.
There was a problem hiding this comment.
🍏 nit: Apparently (IIRC from Wieland) "string" enums are preffered to integers for their speaking nature in db exports, whenever those happen. However, doing a quick search across enum definitions does not support this 🤷🏾
There was a problem hiding this comment.
@akabiru that's also a good point. If we have previously made such decisions, then I need to rollback to a text field.
There was a problem hiding this comment.
I'll poke around a bit further following the guide that @thykel linked 👀
2922d47 to
4826e52
Compare
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
| it "is valid with kind 'target'" do | ||
| record.kind = "target" | ||
| expect(record).to be_valid | ||
| end | ||
|
|
||
| it "is valid with kind 'observed_in'" do | ||
| record.kind = "observed_in" | ||
| expect(record).to be_valid | ||
| end |
There was a problem hiding this comment.
🍏 can be simplified- assumes string backed enum (no strong preference)
| it "is valid with kind 'target'" do | |
| record.kind = "target" | |
| expect(record).to be_valid | |
| end | |
| it "is valid with kind 'observed_in'" do | |
| record.kind = "observed_in" | |
| expect(record).to be_valid | |
| end | |
| it do | |
| expect(subject).to define_enum_for(:kind) | |
| .with_values(target: "target", observed_in: "observed_in") | |
| .backed_by_column_of_type(:string) | |
| end |
e90ea69 to
d375c36
Compare
| def permitted_params | ||
| RequestStore.fetch(:permitted_params) { PermittedParams.new(params, User.current) } | ||
| end | ||
| class WorkPackageVersion < ApplicationRecord |
There was a problem hiding this comment.
You could name this "WorkPackage::Version". (Then the file goes to app/models/work_package/version). This helps to keep the global namespace overseeable.
There was a problem hiding this comment.
I like the idea of scoping models, but I don't like having two models called version.rb. That and the fact that WorkPackage & Version are both core models of OpenProject. We could discuss for example if the model should be scoped the other way around Version::WorKPackage.
So at this moment I'd prefer to keep it work_package_version.
Open to being convinced otherwise, though.
There was a problem hiding this comment.
Since WorkPackageVersion is a join table, I don't think the namespacing semantics apply here, and we're better off keeping it as-is.
With that said, it would be nice to pin down a single specific convention in place for these join tables -- AFAIK this is one of the two that are currently in use (= just concatenating the names of both models).
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
|
@judithroth @akabiru since this is not easilly reversible if I press merge, I'll wait for your follow up before pressing the button. |
| end | ||
| class CreateWorkPackageVersions < ActiveRecord::Migration[8.1] | ||
| def change | ||
| create_enum :work_package_version_kind, ["target", "observed_in"] |
Ticket
https://community.openproject.org/projects/STC/work_packages/STC-847/activity
What are you trying to accomplish?
Establish a new database model to enable building multiple versions fields on work packages
What approach did you choose and why?
Merge checklist