URL helper for has_many relationship

Hi everyone,

new (or rather returning) casual rails user. I had a project for which I needed a database with web-gui, so I figured - rails, why not.

With that said (i.e. I am not super firm on all the technical details and am trying to somewhat complex things without much experience in rails ;)…

I have the following models:

class Sample
   has_many :assemblies
end

class Assemblies
   belongs_to :sample
end

and the routes I have, among other things:

resources :samples do
   resources :assemblies
end

Simple enough. I was expecting that I can list all the assemblies belonging to a sample with:

<%= link_to "Assemblies", sample_assemblies_path(sample) %>

Yet this will list all the assemblies in the database, not just the assemblies belonging to the sample I am passing as an argument.

I am clearly misunderstanding something fundamental here… I know that I can extend the assembly controller to check for the presence of params[:sample_id] and build the @assemblies array in that manner. But it seems to me that with all the “magic” happening in rails, this should work “automatically”.

Any clarification would be appreciated!

Rails version is 7.1

Assuming that your example is typed in off the top of your head (because I don’t see your classes inheriting from ActiveRecord::Base or ApplicationRecord), what I can see right away is that your Assemblies class wants to be Assembly (singular). Try changing that (go back through generating your models, don’t just change the name of the class). See what changes or if it suddenly starts working.

Walter

Not AFAIK. You need to define that. The nested route alone won’t provide that scoping of the records.

The controller needs to be updated to handle the nested route, true. If you fix the model name, and don’t do anything else to the routes, you should see a route that looks something like this:

# rails routes =>
sample_assemblies  GET  /samples/:sample_id/assemblies(.:format)  assemblies#index

This tells you that the assemblies controller needs to become aware of the fact that it may need to consider the sample_id parameter when calling its index method.

If you were to do this all inside that method (not using any before_action methods to set everything up) then it might look something like this:

def index
  if params[:sample_id]
    sample = Sample.find params[:sample_id]
    @assemblies = sample.assemblies
  else
    @assemblies = Sample.all
  end
end

If you are never going to later add a route that looks like just /assemblies, pointed at that same AssembliesController#index method, then you don’t even need to add that conditional statement in there. It can be reduced to:

def index
  sample = Sample.find params[:sample_id]
  @assemblies = sample.assemblies
end

Walter

Thanks! Yes, that was the solution I was aware of, but it seemed that this should somehow be taken care of by rails through the fact that the model does specify this dependency. But adding it in the controller isn’t a big deal - I just wanted to make sure I am not going the long way around, as it were.