Repository: okuramasafumi/alba (Ruby)

Issue:
Method Context Issue in Alba::Resource Trait Blocks
## Describe the bug
When defining attributes inside a trait block in `Alba::Resource`, instance methods (including those from included modules) are not accessible within the attribute block, resulting in a `NoMethodError`. The same methods work correctly when defined directly in the resource class without traits.

## To Reproduce
Steps to reproduce the behavior:

1. Create a resource class that includes `Alba::Resource` and a module with shared methods
2. Define an attribute within a trait block that calls a method from the included module
3. Serialize the resource with the trait enabled

```ruby
module SharedLogic
  def shared_method(name)
    "Shared#{name}"
  end
end

class FooResource
  include Alba::Resource
  include SharedLogic

  attributes :id

  trait :additional do
    attribute :name do |foo|
      shared_method(foo.name)  # This raises NoMethodError
    end
  end
end

foo = Foo.new(1, 'Name')
FooResource.new(foo, with_traits: :additional).serialize # => NoMethodError: undefined method 'shared_method' for an instance of #<Class:0x000000017eada320>
```

## Expected behavior
The attribute block within the trait should have access to instance methods and methods from included modules, just like attribute blocks defined directly in the resource class. The serialization should complete successfully and return `'{"id":1, "name":"SharedName"}'`.

## Actual behavior
A `NoMethodError` is raised: `undefined method 'shared_method' for an instance of #<Class:0x000000017eada320>`. The attribute blocks within traits appear to be executed in a different context where instance methods are treated as class methods.

## Environment
Ruby version: 3.4.4
Alba gem version: 3.7.3

## Additional context
The problem affects both methods from included modules and instance methods defined within the resource class itself.

```ruby
# Private instance method example that also fails in traits
class FooResource
  include Alba::Resource

  attributes :id

  trait :additional do
    attribute :name do |foo|
      format_name(foo.name)  # NoMethodError: undefined method 'format_name'
    end
  end

  private

  def format_name(name)
    "Formatted: #{name}"
  end
end

foo = Foo.new(1, 'Name')
FooResource.new(foo, with_traits: :additional).serialize
# => NoMethodError: undefined method 'format_name' for an instance of #<Class:0x000000017eada320>
```

This issue prevents the use of shared logic and helper methods within trait-based attributes. The same code works perfectly when the attribute is defined directly in the resource class without using traits:

```ruby
# This works fine
class FooResource
  include Alba::Resource
  include SharedLogic

  attributes :id

  attribute :shared_name do |foo|
    shared_method(foo.name)  # This works
  end

  attribute :formatted_name do |foo|
    format_name(foo.name)  # This works too
  end

  private

  def format_name(name)
    "Formatted: #{name}"
  end
end
```



Discussion:
@ether-moon Thank you for submitting an issue. I've confirmed that it's a bug. There's a `helper` method that could be used here, but that doesn't work with `trait`.
I'll fix it with the improvement on `helper`.
@okuramasafumi I have fixed this issue. Please check the PR #452 



Patch:
diff --git a/lib/alba/resource.rb b/lib/alba/resource.rb
index ad74af7..de9920a 100644
--- a/lib/alba/resource.rb
+++ b/lib/alba/resource.rb
@@ -113,18 +113,15 @@ def serializable_hash
       private
 
       def hash_from_traits(obj)
-        h = {}
-        return h if @with_traits.nil?
+        return {} if @with_traits.nil?
 
-        Array(@with_traits).each do |trait|
+        Array(@with_traits).each_with_object({}) do |trait, hash|
           body = @_traits.fetch(trait) { raise Alba::Error, "Trait not found: #{trait}" }
-
-          resource_class = Alba.resource_class
+          resource_class = Class.new(self.class)
           resource_class.class_eval(&body)
           resource_class.transform_keys(@_transform_type) unless @_transform_type == :none
-          h.merge!(resource_class.new(obj, params: params, within: @within, select: method(:select)).serializable_hash)
+          hash.merge!(resource_class.new(obj, params: params, within: @within, select: method(:select)).serializable_hash)
         end
-        h
       end
 
       def deprecated_serializable_hash


Test patch:
diff --git a/test/usecases/trait_test.rb b/test/usecases/trait_test.rb
index b52cf5e..68f326d 100644
--- a/test/usecases/trait_test.rb
+++ b/test/usecases/trait_test.rb
@@ -105,4 +105,48 @@ def test_it_works_with_association_with_traits
       UserResourceWithProfile.new(@user, with_traits: :with_profile).serialize
     )
   end
+
+  class UserResourceWithInstanceMethod < UserResource
+    trait :formatted_name do
+      attribute :formatted_name do
+        format_name
+      end
+    end
+
+    private
+
+    def format_name
+      "Mr./Ms. #{object.name}"
+    end
+  end
+
+  def test_it_works_with_instance_method_in_trait
+    assert_equal(
+      '{"id":1,"formatted_name":"Mr./Ms. Masafumi OKURA"}',
+      UserResourceWithInstanceMethod.new(@user, with_traits: :formatted_name).serialize
+    )
+  end
+
+  module FormatNameExtension
+    def format_name
+      "Mr./Ms. #{object.name}"
+    end
+  end
+
+  class UserResourceWithExtension < UserResource
+    include FormatNameExtension
+
+    trait :formatted_name do
+      attribute :formatted_name do
+        format_name
+      end
+    end
+  end
+
+  def test_it_works_with_extension_in_trait
+    assert_equal(
+      '{"id":1,"formatted_name":"Mr./Ms. Masafumi OKURA"}',
+      UserResourceWithExtension.new(@user, with_traits: :formatted_name).serialize
+    )
+  end
 end