has_one, belongs_to What am I doing wrong? - ruby-on-rails

I have Users and each user sets a Goal. So a goal belongs_to a user and a user has_one: goal. I am trying to use form_for in the view to allow the user to set their goal up.
I figured it would be like microposts (which is straight from Hartl's tutorial) just with singular instead of plural. I've looked at tutorials and questions on here for this issue and tried numerous different things and I just can't get it working.
I got the form_for actually working and apparently pointing to the correct route, but I'm getting the below error and I have no clue what it means:
undefined method `stringify_keys' for "Lose Weight":String
GoalsController
class GoalsController < ApplicationController
before_filter :signed_in_user
def create
#goal = current_user.build_goal(params[:goal])
if #goal.save
redirect_to #user
end
end
def destroy
#goal.destroy
end
def new
Goal.new
end
end
Goal Model
class Goal < ActiveRecord::Base
attr_accessible :goal, :pounds, :distance, :lift_weight
belongs_to :user
validates :user_id, presence: true
end
User Model
class User < ActiveRecord::Base
has_one :goal, :class_name => "Goal"
end
_goal_form (which is a modal on the Users#show)
<div class="modal hide fade in" id="goal" >
<%= form_for(#goal, :url => goal_path) do |f| %>
<div class="modal-header">
<%= render 'shared/error_messages', object: f.object %>
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>What's Your Health Goal This Month?</h3>
</div>
<div class="modal-body">
<center>I want to <%= select(:goal, ['Lose Weight'], ['Exercise More'], ['Eat Better']) %> </center>
</div>
<div class="modal-body">
<center>I will lose <%= select_tag(:pounds, options_for_select([['1', 1], ['2', 1], ['3', 1], ['4', 1], ['5', 1], ['6', 1], ['7', 1], ['8', 1], ['9', 1], ['10', 1]])) %> lbs. this month!</center>
</div>
<div class="modal-footer" align="center">
Close
<%= f.submit "Set Goal", :class => "btn btn-primary" %>
</div>
<% end %>
</div>
Routes.rb
resource :goal, only: [:create, :destroy, :new]

I expect the stringify_keys error is down to the way you've listed your options in the goal field, they need to be grouped up to be treated as one argument.
Along with using accepts_nested_attributes_for :goal as suggested by Dipak, you will want to have a nested form.
form_for #user do |form|
fields_for #goal do |fields|
fields.select :goal, ['Lose Weight', 'Exercise More', 'Eat Better']
The save action is now in the context of a user, so the attributes that come through will include a portion for the goal fields:
user =>{goal_attributes => {:goal => 'Eat Better'}}
You can save these attributes by updating the user:
#user.update_attributes(params[:user])
As an aside, your "new" action should be #goal = Goal.new, just creating a new goal does nothing, you need to assign it to a variable for it to make it to the page.
Good luck!

try this
# in your user model
accepts_nested_attributes_for :goal
write above code in your user model, and
for select tag try to use from this link
http://shiningthrough.co.uk/Select-helper-methods-in-Ruby-on-Rails

Related

NoMethodError - Ruby on Rails

I'm working through Code4Startup airbnb course (https://code4startup.com/projects/build-airbnb-with-ruby-on-rails-level-1) but I'm trying to adapt it for my own idea - an airbnb for education courses for my local colleges. I'm new to ruby and stackoverflow, I've tried searching for the solution for ages but my issue is that I don't know how to correctly describe it, so please explain it like I'm 5!
The error I'm receiving:
The error seems to be suggesting that my course model isn't being built correctly or that it is reverting back to the Listing model somehow (perhaps because my course_params aren't correct?)
NoMethodError in Courses#new
Showing /Users/Jack_R/code/rails/planet_study/app/views/courses/new.html.erb where line #22 raised:
undefined method `type' for #<Listing:0x007fc25da72ea8>
Extracted source (around line #22):
20
21
22
<div class="form-group">
<label>Course Type</label>
<%= f.select :type, [["English Language", "English Language"], ["Culture", "Culture"], ["Sports", "Sports"], ["Tech/Science", "Tech/Science"], ["Adventure", "Adventure"], ["Mixture", "Mixture"]],
id: "type", prompt: "Select...", class: "form-control" %>
</div>
</div>
My Models
I have a User model, a Listing model and a Course model (User>Listing>Course):
class User < ApplicationRecord
has_many :listings
has_many :courses, :through => :listings
end
Listing model:
class Listing < ApplicationRecord
belongs_to :user
has_many :courses
end
Course model:
class Course < ApplicationRecord
belongs_to :listing
end
Courses Controller
class CoursesController < ApplicationController
before_action :set_course, except: [:index, :new, :create]
before_action :authenticate_user!, except: [:show]
def index
#courses = current_user.listings.courses
end
def new
#course = current_user.listings.build
end
def create
#course = listings.build(course_params)
if #course.save
redirect_to listing_course_path(#course), notice: "Saved..."
else
render :new, notice: "Something went wrong..."
end
end
def show
def listing
end
def pricing
end
def description
end
def photo_upload
end
def amenities
end
def location
end
def update
if #course.update(course_params)
flash[:notice] = "Saved..."
else
flash[:notice] = "Something went wrong..."
end
redirect_back(fallback_location: request.referer)
end
private
def set_course
#course = Course.find(params[:id])
end
def room_params
params.require(:course).permit(:name, :type, :summary, :address, :places, :start_date, :finish_date, :price)
end
end
end
Course new.html.erb
<div class="panel panel-default">
<div class="panel-heading">
Create your course listing
</div>
<div class="panel-body">
<div class="devise-container">
<%= form_for #course do |f| %>
<div class="row">
</div>
<div class="col_md_4 select">
<div class="form-group">
<label>Course Type</label>
<%= f.select :type, [["English Language", "English Language"], ["Culture", "Culture"], ["Sports", "Sports"], ["Tech/Science", "Tech/Science"], ["Adventure", "Adventure"], ["Mixture", "Mixture"]],
id: "type", prompt: "Select...", class: "form-control" %>
</div>
</div>
<div class="col_md_4 select">
<div class="form-group">
<label>Places</label>
<%= f.select :places, [["1", 1], ["2", 2], ["3", 3], ["4", 4], ["5", 5], ["6", 6], ["7", 7]],
id: "places", prompt: "Select...", class: "form-control" %>
</div>
</div>
</div>
<div><%= f.submit "Create My Course", class: "btn btn-primary-green" %></div>
<% end %>
</div>
</div>
</div>
type is a reserved word in Rails. You can create a model with a type attribute, but you can't perform actions on this model until you rename the type attribute.
If you try to create a new record, through the rails console, you'll see a message like:
$ rails console
[1] pry(main)> Course.new(name: 'first', type: 'some type')
ActiveRecord::SubclassNotFound: The single-table inheritance mechanism
failed to locate the subclass: 'some type'. This error is raised because
the column 'type' is reserved for storing the class in case of
inheritance. Please rename this column if you didn't intend it to be
used for storing the inheritance class or overwrite
Course.inheritance_column to use another column for that information.
from
/Users/***/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.1.4/lib/active_record/inheritance.rb:196:in
`rescue in find_sti_class'
As the message says, you must rename the type attribute to be able to work with it, to do it just run a migration to change this name and edit the file created, like:
$ rails generate migration rename_type_to_type_of
In the generated file use the rename_colum method, and specify first the model, then the old attribute name, and then the new one, like:
class RenameTypeToTypeOf < ActiveRecord::Migration[5.1]
def change
rename_column :courses, :type, :type_of
end
end
After that you can run rails db:migrate. Note type_of is just a poor suggestion of mine, you can adapt it as you want.

Ruby on Rails - No method error

I'm completing this airbnb clone course (https://code4startup.com/projects/build-airbnb-with-ruby-on-rails-level-1) but have diverted a bit in order to complete my own project; a marketplace for education camps. Therefore I've added an additional model. It now has User>Listing>Course.
Since adding this course I keep receiving the following error upon running the server and going to localhost:3000/courses/new I've tried searching for the problem on stackoverflow but I'm not experienced enough to describe and therefore find the issue, I'd appreciate any ideas.
Error Message
undefined method `curriculum_type' for #<Listing:0x007fb776ac0f50>
Extracted source (around line #15):
<div class="form-group">
<label>Course Type</label>
<%= f.select :curriculum_type, [["English Language", "English Language"], ["Culture", "Culture"], ["Sports", "Sports"], ["Tech/Science", "Tech/Science"], ["Adventure", "Adventure"], ["Mixture", "Mixture"]],
id: "type", prompt: "Select...", class: "form-control" %>
</div>
</div>
Models
class User < ApplicationRecord
has_many :listings
has_many :courses, :through => :listings
end
class Listing < ApplicationRecord
belongs_to :user
has_many :courses
end
class Course < ApplicationRecord
belongs_to :listing
end
Courses Controller
class CoursesController < ApplicationController
before_action :set_course, except: [:index, :new, :create]
before_action :authenticate_user!, except: [:show]
def index
#courses = current_user.listings.courses
end
def new
#course = current_user.listings.build
end
def create
#course = listings.build(course_params)
if #course.save
redirect_to listing_course_path(#course), notice: "Saved..."
else
render :new, notice: "Something went wrong..."
end
end
def show
def listing
end
def pricing
end
def description
end
def photo_upload
end
def amenities
end
def location
end
def update
if #course.update(course_params)
flash[:notice] = "Saved..."
else
flash[:notice] = "Something went wrong..."
end
redirect_back(fallback_location: request.referer)
end
private
def set_course
#course = Course.find(params[:id])
end
def room_params
params.require(:course).permit(:name, :course_type, :summary, :address, :course_places, :start_date, :finish_date, :price)
end
end
end
Courses new.html.erb
<div class="panel panel-default">
<div class="panel-heading">
Create your course listing
</div>
<div class="panel-body">
<div class="devise-container">
<%= form_for #course do |f| %>
<div class="row">
</div>
<div class="col_md_4 select">
<div class="form-group">
<label>Course Type</label>
<%= f.select :curriculum_type, [["English Language", "English Language"], ["Culture", "Culture"], ["Sports", "Sports"], ["Tech/Science", "Tech/Science"], ["Adventure", "Adventure"], ["Mixture", "Mixture"]],
id: "type", prompt: "Select...", class: "form-control" %>
</div>
</div>
<div class="col_md_4 select">
<div class="form-group">
<label>Places</label>
<%= f.select :course_places, [["1", 1], ["2", 2], ["3", 3], ["4", 4], ["5", 5], ["6", 6], ["7", 7]],
id: "places", prompt: "Select...", class: "form-control" %> -->
</div>
</div>
</div>
<div><%= f.submit "Create My Course", class: "btn btn-primary-green" %></div>
<% end %>
</div>
</div>
</div>
In Rails Console I can create all models, but it seems that it is not recognising the Courses Model when I start the server
Your controller is building a Listing object, but your curriculum_type attribute is an attribute for a Course. You'll want to modify your controller to be building a Course object if that's the case, or add the attribute to Listing.

Ancestry Gem for Nested Comments with Rails causing undefined method error

I have been trying to fix an error associated with using the Ancestry gem for comments on my app for Rails 4. I used railscast episode 262 as a guide. However, unlike the episode, my comments model is a nested resource inside another model.Before I go further, I will supply the necessary code for reference. If you like to read the error right away, it is mentioned right after all the code snippets.
The Relevant Models:
class Comment < ActiveRecord::Base
has_ancestry
belongs_to :user
belongs_to :scoreboard
end
class Scoreboard < ActiveRecord::Base
#scoreboard model is like an article page on which users can post comments
belongs_to :user
has_many :teams, dependent: :destroy
has_many :comments, dependent: :destroy
end
Relevant code in the route file:
resources :scoreboards do
resources :comments
resources :teams, only: [:edit, :create, :destroy, :update]
end
The Scoreboards Controller Method for the page on which one can post comments:
def show
#scoreboard = Scoreboard.find_by_id(params[:id])
#team = #scoreboard.teams.build
#comment = #scoreboard.comments.new
end
The Comments Controller:
class CommentsController < ApplicationController
def new
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#comment = #scoreboard.comments.new(:parent_id => params[:parent_id])
end
def create
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#comment = #scoreboard.comments.new comment_params
if #comment.save
redirect_to scoreboard_url(#comment.scoreboard_id)
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:body, :parent_id).merge(user_id: current_user.id)
end
end
I will include the migration for the ancestry gem if any mistakes were made on that :
class AddAncestryToComments < ActiveRecord::Migration
def change
add_column :comments, :ancestry, :string
add_index :comments, :ancestry
end
end
The following code shows the view code:
Scoreboard#show View which is giving me the error in the last line:
<div class= "comment-section">
<%= form_for [#scoreboard, #comment] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_area :body, class: "comment-field" %>
<%= f.hidden_field :parent_id %> #is it needed to include this here? because this form is for new comments not replies
<%= f.submit "Join the discussion...", class: " comment-button btn btn-primary" %>
<% end %>
<%= nested_comments #scoreboard.comments.reject(&:new_record?).arrange(:order => :created_at) %>
</div>
The (comments partial)_comment.html.erb View:
<div class=" comment-div">
<p> Posted by <%= link_to "#{comment.user.name}", comment.user %>
<%= time_ago_in_words(comment.created_at) %> ago
</p>
<div class="comment-body">
<%= comment.body %>
<%= link_to "Reply", new_scoreboard_comment_path(#scoreboard, comment, :parent_id => comment) %>
</div>
</div>
The helper method to render comments:
def nested_comments(comments)
comments.map do |comment, sub_comment| #the comments.map also gives me an error if I choose to render the comments without the .arrange ancestry method
render(comment) + content_tag(:div, nested_comments(sub_comment), class: "nested_messages")
end.join.html_safe
end
The new.html.erb for Comments which one is redirected to for the replies form submission:
<%= form_for [#scoreboard, #comment] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_area :body, class: "comment-field" %>
<%= f.hidden_field :parent_id %>
<%= f.submit "Join the discussion...", class: " comment-button btn btn-primary" %>
<% end %>
Upon creating a scoreboard, I am redirected to the show page, where i get the following error:
undefined method `arrange' for []:Array
Even though the array of comments is empty, I get the same error if it wasnt. I have tried .subtree.arrange but that gives me the same error. Also, the ancestry documentation said that .arrange works on scoped classes only. I don't know what that means. I would appreciate some help on making the page work so the comments show properly ordered with the replies after their parent comments. If this is the wrong approach for threaded comments(replies and all), I would appreciate some guidance on what to research next.
.reject(&:new_record?) this will return an array. The error sounds like arrange is a scope on ActiveRecord. So move the reject to the end and it should work.
#scoreboard.comments.arrange(:order => :created_at).reject(&:new_record?)
In regards your comment nesting, I have implemented this before, and found the Railscasts recommendation of a helper to be extremely weak.
Passing parent_id to a comment
Instead, you're better using a partial which becomes recursive depending on the number of children each comment has:
#app/views/scoreboards/show.html.erb
<%= render #comments %>
#app/views/scoreboards/_comment.html.erb
<%= link_to comment.title, comment_path(comment) %>
<div class="nested">
<%= render comment.children if comment.has_children? %>
</div>

How to pass instance variables through link_to, to call js file, which renders a partial?

My app consists of four models. User > List > Wish < Item. I'm showing all the items on the front page, and want to be able to build a wish from the individual items.
Because of the associations I have to enable to user to specify which list he want to associate the item with. I want to do through an ajax call and a modal. However, the instance variable item in the _item.html.erb partial can't be passed through a link_to, which calls app/views/wishes/new.js.erb, which renders a form to specify the list.
I'm very new to rails and ruby, and this problem have been troubling me for days! Any help is thus much appreciated.
The associations:
class User < ActiveRecord::Base
has_many :lists, dependent: :destroy
has_many :wishes, through: :lists
has_many :items, through: :wishes
end
class List < ActiveRecord::Base
belongs_to :user
has_many :wishes, dependent: :destroy
has_many :items, through: :wishes
end
class Wish < ActiveRecord::Base
belongs_to :list, touch: true
belongs_to :item
end
class Item < ActiveRecord::Base
has_many :wishes
has_many :lists, through: :wishes
end
app/views/static_pages/home.html.erb
<%= render #items %>
app/views/items/_item.html.erb
<div class="span4">
<div class="white-box item">
<div class="image-container">
<%= link_to "Wishlistt it", new_wish_path(item_id: item.id), id: "new_wish", class: "btn btn-primary btn-large", remote: true %>
<a href="<%= item_path(item) %>" class="item-link">
<em class="mark"></em>
<%= image_tag item.image_url(:medium).to_s %>
</a>
</div>
<h3><%= item.title %></h3>
<%= item.wishes.count %> wishes this item
</div>
</div>
app/views/wishes/new.js.erb
$('body').append('<%= j render "new_wish" %>');
$('#new_wish').modal('toggle')
app/views/wishes/_new_wish.html.erb
<div id="new_wish" class="modal hide fade" tabindex="1" role="dialog" aria-labelledby="make_wish" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="wishlistt_it">Wishlistt it</h3>
</div>
<div id="linkpreview">
<div class="modal-body">
<%= form_for(#item.wishes.build(item_id: #item.id)) do |f| %>
<%= f.hidden_field :item_id %>
<%= f.label :list_id %>
<%= select_tag :list_id, options_for_select(current_user.lists.all.collect{ |u| [u.name, u.id] }) %>
<%= f.submit "Add wish", class: "btn btn-large btn-primary" %>
<% end %>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<%= link_to "Get info", new_item_path, id: "urlb", class: "btn btn-primary", remote: true %>
</div>
</div>
</div>
Pressing the link from _item.html.erb raises this error:
undefined method `wishes' for nil:NilClass
EDIT
wishes_controller.rb
class WishesController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
before_filter :correct_user, only: :destroy
def new
#wish = Wish.new
end
def create
#item = Item.find_by_id(params[:item_id])
#wish = Wish.create!(item_id: params[:wish][:item_id], list_id: params[:list_id])
redirect_to root_url
end
def destroy
#wish.destroy
redirect_to current_user
end
private
def correct_user
#wish = current_user.wishes.find_by_id(params[:id])
redirect_to current_user if #wish.nil?
end
end
First of all, how path_heplers work.
new_wish_path
will produce route
/wishes/new
which, for default, will be looking for wishes#new method, which you actually don't have.
New action is needed to GET object form, and create method saves inputed data in database - this is default Rails logic.
Here you don't have form, that means, you don't pass params[:wish](it is nil).
Also, in create method you need to use save method, which saves inputed data to DB.
In conclusion, in my opinion, this code is really far enough from something that can be edited and that can work normally. Anyway, I recommend to refactor this code following provided here tips, from very beggining, it will save you time for sure.
UPD
Steps to fix:
1) add new method in wishes_contoller
2) define there instance #item for form, finding it by params in request: #item = Item.find_by_id(params[:item_id])

Rails has_many checkboxes with extra attribtues

We have the following code working for a complex rails form with checkboxes. I'm not really happy with the solution we have in place and I was wondering if anyone knows of a more proper way to do this in rails. All the code below is working I just want to know if there is a cleaner approach.
In my Admins controller I want to remove the need to call the following code on each update.
#user.admin.school_admin_roles.destroy_all
params[:roles].each do |school_role|
ids = school_role.split('_')
#user.admin.school_admin_roles.find_or_create_by_school_id_and_school_role_id(ids[0], ids[1])
end if !params[:roles].nil?
So I basically want to be able to call #user.update_attributes(params[:user]) and have rails take care of creating the needed relationships for me. I have that working with AccountRole in the form below. I want to know if there is a way to do the same thing with SchoolRole given I have an extra variable school_id in the join table.
We have the following form for editing a user and assigning roles
Screenshot of form ->
http://i.stack.imgur.com/PJwbf.png
I have the following form where an admin can edit other users and assign account based roles and school based roles via checkboxes. The account based roles were easy to implement. The school based rules are a bit complicated since the join table school_admin_roles has school_id, user_id, role_id fields. We had to implement the school roles part of the form in a rather hackish way. We have the form implemented like this - notice how we hacked together school.id.to_s+'_'+role.id.to_s into the same checkbox on school roles.
In the Admins controller's update function we manually destroy all school_admin roles on each update then loop through the school roles params do a split on the ids on '-' then manually re-create each school based role. I really hate the way we've had to go about this. Could anyone shed some light on a cleaner more rails centric approach to solving this scenario?
The form -
<%= form_for #user, :url => {:controller => 'admins', :action => 'update'} do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.fields_for :admin do |uf| %>
<div class="field">
<%= uf.label :first_name %>
<%= uf.text_field :first_name %>
</div>
<label>Admin Permissions</label>
#account level permissions works fine
<%= hidden_field_tag "#{uf.object_name}[account_role_ids][]" %>
<% AccountRole.find(:all).each do |role| %>
<div class="account_role">
<%= check_box_tag "#{uf.object_name}[account_role_ids][]", role.id, #user.admin.account_roles.include?(role)%>
<%= role.name %>
</div>
<% end %>
#school level permissions a bit of a hack
<%= hidden_field_tag "#{uf.object_name}[school_role_ids][]" %>
<% SchoolRole.find(:all).each_with_index do |role, index| %>
<div class="school_role">
<%= check_box_tag "#{uf.object_name}[school_role_ids][]",role.id, #user.admin.school_roles.include?(role) %>
<%= role.name %>
<span class="advanced_box admin_permissions" <% if #user.admin.school_roles.include?(role) %>style="display:inline"<% end %>>
<div class="content" id="perm_<%= index %>">
<h4><%= role.name %></h4>
<% uf.object.account.schools.each do |school|%>
<div>
<%= check_box_tag "roles[]", school.id.to_s+'_'+role.id.to_s, role.school_admin_roles.where(:admin_id => uf.object.id).collect(&:school_id).include?(school.id)%>
<%= school.name %>
</div>
<% end %>
<%= link_to 'Done', '#', :class => "done" %>
</div>
Advanced
</span>
</div>
<% end %>
</div>
<% end %>
The controller
class AdminsController < ApplicationController
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
# TODO find a way to refactor this
#user.admin.school_admin_roles.destroy_all
params[:roles].each do |school_role|
ids = school_role.split('_')
#user.admin.school_admin_roles.find_or_create_by_school_id_and_school_role_id(ids[0], ids[1])
end if !params[:roles].nil?
#
flash[:notice] = "Successfully updated Admin."
redirect_to admins_path
else
render "edit"
end
end
end
Given the following models
class User < ActiveRecord::Base
has_one :parent
has_one :admin
has_many :scool_admin_roles
has_many :account_admin_roles
end
class AccountAdminRole < ActiveRecord::Base
before_save :set_account_id
belongs_to :admin
belongs_to :account_role
end
class SchoolAdminRole < ActiveRecord::Base
belongs_to :admin
belongs_to :school_role
belongs_to :school
end
class SchoolRole < ActiveRecord::Base
has_many :school_admin_roles
end
class AccountRole < ActiveRecord::Base
has_many :account_admin_role
end
When I face code that I know smells bad, usually it leads me to the design.
In this case, the problem is the database table design.
You are hacking the value passed from a checkbox with a delimiter because the "join" table does more than just join. I believe that the relationship to school belongs_to the SchoolRole and not the SchoolAdminRole. Changing this will create a pattern much like your AccountRole.
Correcting the model design, might be a bit painful now, but it is much cleaner and will be maintainable in the future. You will thank yourself later.
We refactored the code above as follows
In the model we added accepts_nested_attributes_for :school_admin_roles, :reject_if => proc { |attr| attr['school_role_id'].blank? }
and added school_admin_roles_attributes to attr_accessible
class Admin < ActiveRecord::Base
belongs_to :account
belongs_to :user
has_many :school_admin_roles
has_many :school_roles, :through => :school_admin_roles
has_many :account_admin_roles
has_many :account_roles, :through => :account_admin_roles
accepts_nested_attributes_for :account
accepts_nested_attributes_for :school_admin_roles, :reject_if => proc { |attr| attr['school_role_id'].blank? }
attr_accessible :account_role_ids, :email, :first_name, :last_name, :account_id, :user_id, :account_attributes, :school_admin_roles_attributes
default_scope where(:deleted => false)
end
We then built the form as follows
<% index2 = 0 %>
<% SchoolRole.find(:all).each_with_index do |role, index| %>
<div class="school_role">
<%= check_box_tag "school_roles[]",role.id, #user.admin.school_roles.include?(role) %>
<%= role.name %>
<span class="advanced_box admin_permissions" <% if #user.admin.school_roles.include?(role) %>style="display:inline"<% end %>>
div class="content" id="perm_<%= index %>">
<h4><%= role.name %></h4>
<% uf.object.account.schools.each do |school|%>
<div>
<%= check_box_tag "#{uf.object_name}[school_admin_roles_attributes][#{index2}][school_role_id]", role.id, role.school_admin_roles.where(:admin_id => uf.object.id).collect(&:school_id).include?(school.id)%>
<%= school.name %>
<%= hidden_field_tag "#{uf.object_name}[school_admin_roles_attributes][#{index2}][school_id]", school.id %>
</div>
<% index2 += 1 %>
<% end %>
<%= link_to 'Done', '#', :class => "done" %>
</div>
Advanced
</span>
</div>
<% end %>
</div>
<% end %>
Which then enabled us to refactor the controller without splitting the ids but we still have to call destroy all each time which I can live with.
def update
#user = User.find(params[:id])
#user.admin.school_admin_roles.destroy_all
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully updated Admin."
redirect_to admins_path
else
render "edit"
end
end

Resources