In the edit method of many controllers you initialize a new object and edit existing objects
class MagazinesController < ApplicationController
def edit
@magazine = Magazine.find(params[:magazine_id])
@page = Page.find(params[:id])
@new_page = @magazine.pages.new
end
end
However in a view you will often want to cycle through the persisted objects and treat the new object separately
# magazines#edit
%h4 Existing pages
- @magazine.pages.each do |page|
%p= link_to page, page.title
...is that the pages
association contains both existing (persisted) pages but also the new page which we made via @new_page = @magazine.pages.new
.
It's easy to deal with this however it's ugly
%h4 Existing pages
- @magazine.pages.each do |page|
- if page.persisted?
%p= link_to page, page.title
I would like to use some assocition method to select only those pages which are persisted:
%h4 Existing pages
- @magazine.pages.persisted.each do |page|
%p= link_to page, page.title
Is there any way of doing this?
Both the suggestions from @Florent2 and @CDub are sound. However @florent2's suggestion meant hitting the database again (and potentially ditching any preset eager loading which I didn't want to do) and @CDub's suggestion didn't quite work out in terms of code. Here is what I ended up going with:
class Magazine < ActiveRecord::Base
has_many :pages do
def persisted
collect{ |page| page if page.persisted? }
end
end
end
this allows you to call .persisted
on any ActiveRecord relation of pages associated with Magazine. It doesn't hit the database again as it simply filters through the pre-loaded objects returning the ones which are persisted.
Since I want to reuse this code on a regular basis I can pull it out into a module
module PersistedExtension
def persisted
select{|item| item if item.persisted?}
end
end
It can then be included into the association methods using a lambda:
class Magazine < ActiveRecord::Base
# ...
has_many :pages, -> { extending PersistedExtension }
end
and I can call it intuitively:
@magazine = Magazine.first
@magazine.pages.persisted
# => array of pages which are persisted
# the new persisted association extension works on any AR result set
@magazine.pages.order('page ASC').persisted