# Excluding columns from inferred schema

**URL:** <https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591>\
**Category:** Issues\
**Created:** [January 31, 2023, 6:18am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591 "2023-01-31T06:18:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![pat](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pat/32/192_2.png) [@pat](https://discourse.rom-rb.org/u/pat)\
**Post date:** [January 31, 2023, 6:18am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/1 "2023-01-31T06:18:35Z")

</div>

Hi all,

I’m working on some migrations to remove columns from a table - and I’d like to first exclude the columns from the returned datasets (like the `ignored_columns` method in ActiveRecord, as recommended by [strong\_migrations](https://github.com/ankane/strong_migrations#removing-a-column)). This is so I can deploy a change to have the column ignored, then later actually remove the column from the database (via migrations) without impacting the running code.

I see that a schema object has [an `exclude` method](https://api.rom-rb.org/rom/ROM/Schema.html#exclude-instance_method) - but I’m not quite sure of the best place to use it. I was hoping it’d be available in the `schema` block in a relation, along the lines of:

```ruby
schema(infer: true) do
  associations do
    # ...
  end

  exclude :useless_column
end

```

But that’s not the case. Is something like this possible in some other manner? (I really don’t want to remove the `infer` option 😓).

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/solnic/32/279_2.png) [@solnic](https://discourse.rom-rb.org/u/solnic)\
**Post date:** [February 2, 2023, 5:58am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/2 "2023-02-02T05:58:51Z")

</div>

You can define a custom dataset and exclude it there, it’s gonna be a bit raw but should work. See here [ROM - Relations](https://rom-rb.org/learn/sql/3.3/relations/#adjusting-default-dataset)

---

<div class="post-metadata">

**Author:** ![pat](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pat/32/192_2.png) [@pat](https://discourse.rom-rb.org/u/pat)\
**Post date:** [February 2, 2023, 6:38am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/3 "2023-02-02T06:38:07Z")

</div>

So something like this should do the trick? (I agree it’s not ideal, but better than specifying all attributes within the schema)

```ruby
dataset do
  select(:list, :all, :other, :columns)
end

```

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/solnic/32/279_2.png) [@solnic](https://discourse.rom-rb.org/u/solnic)\
**Post date:** [February 3, 2023, 8:48am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/4 "2023-02-03T08:48:14Z")

</div>

@pat you can do `exclude` there too

---

<div class="post-metadata">

**Author:** ![pat](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pat/32/192_2.png) [@pat](https://discourse.rom-rb.org/u/pat)\
**Post date:** [February 3, 2023, 12:35pm UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/5 "2023-02-03T12:35:41Z")

</div>

Unfortunately `exclude` within the `dataset` block is for [a negated `where`](https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading.html#exclude-instance_method).

As an alternative, I tried the following:

```ruby
dataset do
  select(*(columns - %I[ignored_column_a ignored_column_b]))
end

```

… but as best as I can tell, this doesn’t get used when the schema infers attributes - so the result is the attributes still exist, but then aren’t populated when querying the database, which understandably raises an exception.

I’ve also looked into creating a schema plugin for this purpose, but plugins are invoked before the inferrer, so there’s no attributes to remove.

My next thought was to change the attributes inferrer on the schema, which… well, this works, but it’s far from elegant, and it hooks into the `filter_columns` method which is tagged as private:

```ruby
class ExcludingInferrer < ROM::SQL::Schema::AttributesInferrer
  option :excluded

  def filter_columns(schema)
    super.reject { |name, _definition| excluded.include?(name) }
  end
end

schema_inferrer schema_inferrer.with(
  attributes_inferrer: -> (schema, gateway, options) do
    builder = ROM::SQL::Schema::TypeBuilder[gateway.database_type]
    inferrer = ExcludingInferrer.new(type_builder: builder, excluded: %I[ignored_column_a ignored_column_b], **options)
    inferrer.(schema, gateway)
  end
)

```

I don’t suppose there’s something I’ve missed about tweaking a schema just before it’s finalised? I’m not against submitting a PR, I’m just not sure what a preferred interface around something like this would be.

---

<div class="post-metadata">

**Author:** ![pat](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pat/32/192_2.png) [@pat](https://discourse.rom-rb.org/u/pat)\
**Post date:** [February 4, 2023, 12:41am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/6 "2023-02-04T00:41:07Z")

</div>

Okay, have found a neater way with a `relation` plugin:

```ruby
class ExcludeAttributes
  def self.apply(relation, names:)
    relation.schema_inferrer Inferrer.new(
      excluded_attributes: names,
      **relation.schema_inferrer.options
    )
  end

  class Inferrer < ROM::SQL::Schema::Inferrer
    option :excluded_attributes, default: -> { [] }

    def call(...)
      super(...).tap do |hash|
        hash[:attributes].reject! do |attribute|
          excluded_attributes.include?(attribute.name)
        end
      end
    end
  end
end

```

Registered as so:

```ruby
ROM.plugins do
  adapter :sql do
    register :exclude_attributes, ExcludeAttributes, type: :relation
  end
end

```

And then in the relation definition:

```ruby
class Users < ROM::Relation[:sql]
  schema :users, infer: true do
    # ... associations, etc
  end

  use :exclude_attributes, names: %i[first_name last_name]

  # ...
end

```

I think I’m happy enough with this approach, but if there’s suggestions on improvements, please do let me know 🙂

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/solnic/32/279_2.png) [@solnic](https://discourse.rom-rb.org/u/solnic)\
**Post date:** [February 6, 2023, 10:12am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/7 "2023-02-06T10:12:08Z")

</div>

Oh wow this is really cool @pat! Thanks for sharing. We could make it a first-class feature in ROM 6.x.

---

<div class="post-metadata">

**Author:** ![pat](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pat/32/192_2.png) [@pat](https://discourse.rom-rb.org/u/pat)\
**Post date:** [February 6, 2023, 10:37am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/8 "2023-02-06T10:37:47Z")

</div>

> We could make it a first-class feature in ROM 6.x.

That’d be great! I can look into writing up a PR if you’d like 🙂

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/alassek/32/260_2.png) [@alassek](https://discourse.rom-rb.org/u/alassek)\
**Post date:** [February 6, 2023, 10:02pm UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/9 "2023-02-06T22:02:23Z")

</div>

This is awesome, thanks for sharing

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/solnic/32/279_2.png) [@solnic](https://discourse.rom-rb.org/u/solnic)\
**Post date:** [February 7, 2023, 11:15am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/10 "2023-02-07T11:15:18Z")

</div>

> [@pat](#):
>
> That’d be great! I can look into writing up a PR if you’d like 🙂

Thanks! We could add it in 6.1. Currently there’s laser-focus on getting 6.0 done for Hanami 2.0 with essential changes/improvements done exclusively. Everything extra will come after 6.0.

---

<div class="post-metadata">

**Author:** ![pboling](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pboling/32/299_2.png) [@pboling](https://discourse.rom-rb.org/u/pboling)\
**Post date:** [June 22, 2023, 7:55am UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/11 "2023-06-22T07:55:58Z")

</div>

Hanami 2.0 has been released, but ROM is still on 5.3. Is there an update on what the current plan is?

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/alassek/32/260_2.png) [@alassek](https://discourse.rom-rb.org/u/alassek)\
**Post date:** [June 22, 2023, 11:37pm UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/12 "2023-06-22T23:37:03Z")

</div>

5.3 was released specifically to support Hanami 2.0. My team is using them together without issue.

Last I heard, official persistence support with ROM was slated for 2.1. There are no full-time developers working on any of this, so timelines are loose.

If you have Hanami-specific questions related to ROM it’s probably best to ask [over on the Hanami board](https://discourse.hanamirb.org/), I can help with that. It’s possible I have the most complicated ROM configuration on Hanami 2.0 currently.

---

<div class="post-metadata">

**Author:** ![pboling](https://yyz1.discourse-cdn.com/flex029/user_avatar/discourse.rom-rb.org/pboling/32/299_2.png) [@pboling](https://discourse.rom-rb.org/u/pboling)\
**Post date:** [June 23, 2023, 6:07pm UTC](https://discourse.rom-rb.org/t/excluding-columns-from-inferred-schema/591/13 "2023-06-23T18:07:30Z")

</div>

At the moment I am planning to use ROM only, and Roda on top for the API, as that aspect of the code is very thin. It is almost all business logic, and ROM + Ruby should be all we need. My interest in the plan for ROM 6.0 is around whether we should start working with the ROM 6.0 alpha / main branch, or start working with 5.3. I think at this point we should stick to 5.3 as 6.0 still seems a bit fluid.
