@kcne commented on this pull request.


> @@ -14,6 +14,10 @@ xml.note("lon" => note.lon, "lat" => note.lat) do
 
   xml.date_closed note.closed_at if note.closed?
 
+  note.tags.each do |k, v|

This code is duplicated multiple times, consider creating a shared helper 
method to reuse instead.

> +  validates :note, :associated => true
+  validates :k, :v, :allow_blank => true, :length => { :maximum => 255 }, 
:characters => true
+  validates :k, :uniqueness => { :scope => :note_id }

To ensure stronger data integrity, we can enforce that k and v are always 
present, within length limits, and unique per note. Additionally, using 
`presence: true` for note simplifies and improves performance compared to 
`associated: true`

```ruby
validates :note, presence: true
validates :k, presence: true, length: { maximum: 255 }, uniqueness: { scope: 
:note_id }
validates :v, presence: true, length: { maximum: 255 }
```

> +class CreateNoteTags < ActiveRecord::Migration[7.2]
+  def change
+    # Create a table and primary key
+    create_table :note_tags, :primary_key => [:note_id, :k] do |t|
+      t.column "note_id", :bigint, :null => false
+      t.column "k",  :string, :default => "", :null => false
+      t.column "v",  :string, :default => "", :null => false
+
+      t.foreign_key :notes, :column => :note_id, :name => "note_tags_id_fkey"
+    end
+  end
+end

This migration works well for ensuring uniqueness with a composite primary key. 
However, if querying by tags (e.g., `{k: "created_by", v: "openstreetmap"}`) is 
expected, a surrogate primary key (`id`) with additional indexes might be more 
efficient. For example:

```ruby
create_table :note_tags do |t|
  t.bigint :note_id, null: false
  t.string :k, null: false, default: ""
  t.string :v, null: false, default: ""

  t.timestamps
end

add_index :note_tags, [:note_id, :k], unique: true       # Enforce uniqueness
add_index :note_tags, [:k, :v]                          # Optimize tag-based 
queries
```

This approach aligns with Rails conventions, simplifies queries, and allows 
adding indexes for tag lookups (`k`/`v`).

> @@ -83,12 +85,30 @@ def create
       lat = OSM.parse_float(params[:lat], OSM::APIBadUserInput, "lat was not a 
number")
       comment = params[:text]
 
+      # Extract the tags parameter (if it exists)
+      tags = []
+      if params[:tags].present?
+        # Split by commas to get individual key-value pairs
+        pairs = params[:tags].split(",")
+
+        # For each pair in parameters, store it in tags variable
+        pairs.each do |pair|
+          key, value = pair.split(":", 2)
+          tags << { :k => sanitize(key), :v => sanitize(value) } if key && 
value
+        end
+      end

I agree with Tom here. Also independent of implementation, validation here 
would be necessary in my opinion.

 Two alternative approaches that could be useful here is to:
- use nested form parameters:
```
tags[created_by]=OpenStreetMap-Website&tags[editor]=JOSM
```
- using a prefix for tag related properties:
```
tag_created_by=OpenStreetMap-Website&tag_editor=JOSM
```

-- 
Reply to this email directly or view it on GitHub:
https://github.com/openstreetmap/openstreetmap-website/pull/5344#pullrequestreview-2475434346
You are receiving this because you are subscribed to this thread.

Message ID: 
<openstreetmap/openstreetmap-website/pull/5344/review/2475434...@github.com>
_______________________________________________
rails-dev mailing list
rails-dev@openstreetmap.org
https://lists.openstreetmap.org/listinfo/rails-dev

Reply via email to