I have a form where I have a table with checkboxes in order to select rows and save IDs in my DB.
But it throws me an error:
Param is missing or the value is empty: leadallocation"
I tried different ways but still nor working. So at the moment I just wand to save the hash in my db. Thanks.
# Never trust parameters from the scary internet, only allow the white list through.
def leadallocation_params
params.require(:leadallocation).permit(:campaign_id, :company_id, :user_id)
end
Request Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"GruGL758jT4FO+t/BTRGLrD2uCGOj/qUCrB5VswquzR9N7JZ/rouLmGZnTE7A+XTARiLwkOy1n3/zMqhzuenmg==",
"company_ids"=>["38",
"40"],
"commit"=>"Create Leadallocation"}
The controller
class LeadallocationsController < ApplicationController
before_action :set_leadallocation, only: [:show, :edit, :update, :destroy]
# GET /leadallocations
# GET /leadallocations.json
def complete
end
def index
#leadallocations = Leadallocation.all
end
# GET /leadallocations/1
# GET /leadallocations/1.json
def show
end
# GET /leadallocations/new
def new
#leadallocation = Leadallocation.new
#comps = Company.all
end
# GET /leadallocations/1/edit
def edit
end
# POST /leadallocations
# POST /leadallocations.json
def create
#leadallocation = Leadallocation.new(leadallocation_params)
#leadallocation.company_id = params[:company_ids]
respond_to do |format|
if #leadallocation.save
format.html { redirect_to #leadallocation, notice: 'Leadallocation was successfully created.' }
format.json { render :show, status: :created, location: #leadallocation }
else
format.html { render :new }
format.json { render json: #leadallocation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /leadallocations/1
# PATCH/PUT /leadallocations/1.json
def update
respond_to do |format|
if #leadallocation.update(leadallocation_params)
format.html { redirect_to #leadallocation, notice: 'Leadallocation was successfully updated.' }
format.json { render :show, status: :ok, location: #leadallocation }
else
format.html { render :edit }
format.json { render json: #leadallocation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /leadallocations/1
# DELETE /leadallocations/1.json
def destroy
#leadallocation.destroy
respond_to do |format|
format.html { redirect_to leadallocations_url, notice: 'Leadallocation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_leadallocation
#leadallocation = Leadallocation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def leadallocation_params
params.require(:leadallocation).permit(:campaign_id, :company_id, :user_id)
end
end
The models
class Leadallocation < ActiveRecord::Base
belongs_to :campaign
belongs_to :company
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_many :activities
belongs_to :campaign
has_many :leadallocations
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Company < ActiveRecord::Base
belongs_to :campaign
has_many :subsidiaries
has_many :leadallocations
end
class Campaign < ActiveRecord::Base
belongs_to :client
has_many :leads
has_many :activities
has_many :contacts
has_many :users
has_many :leadallocations
end
Routes.rb
resources :leadallocations
The view
<h1>New Leadallocation</h1>
<p id="notice"><%= notice %></p>
<h1>Listing Companies</h1>
<%= simple_form_for(#leadallocation) do |f| %>
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Country</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #comps.each do |company| %>
<tr>
<td><%= check_box_tag "company_ids[]", company.id %></td>
<td><%= company.name %></td>
<td><%= company.country %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
<%= link_to 'Back', leadallocations_path %>
The way you are using Strong Params requires that your parameters adhere to a specific form.
In this case, you params need to be nested under the key leadallocation
The problem is in your form, instead of check_box_tag, you will want to do f.check_box and use this documentation to see the available options.
This will nest your attributes under the leadallocation, if it doesn't then something might be wrong with your setup of models and forms.
Basically all this is to say you want to change your params from this:
{"utf8"=>"✓",
"authenticity_token"=>"GruGL758jT4FO+t/BTRGLrD2uCGOj/qUCrB5VswquzR9N7JZ/rouLmGZnTE7A+XTARiLwkOy1n3/zMqhzuenmg==",
"company_ids"=>["38",
"40"],
"commit"=>"Create Leadallocation"}
to this:
{"utf8"=>"✓",
"authenticity_token"=>"GruGL758jT4FO+t/BTRGLrD2uCGOj/qUCrB5VswquzR9N7JZ/rouLmGZnTE7A+XTARiLwkOy1n3/zMqhzuenmg==",
"leadallocation" => {
"company_ids"=>["38","40"]
}
"commit"=>"Create Leadallocation"}
The problem is here:
"company_ids"=>["38", "40"]
It should be:
"leadallocation" => {
"company_ids" => ["38", "40"]
}
This is the standard construct for a Rails object to be passed to your db. This is why strong_params is structured the way it is...
params.require(:top_level_param).permit(:child_params)
--
You can get around this by simply using .permit:
#app/controllers/leadallocations_controller.rb
class LeadAllocationsController < ApplicationController
private
def leadallocation_params
params.permit(:company_ids)
end
end
This is not a permanent fix but a HACK!!!
Fix:
#app/views/lead_allocations/new.html.erb
<%= simple_form_for #leadallocations do |f| %>
<%= f.collection_check_boxes :company_ids, Company.all, :id, :name %>
<%= f.submit %>
<% end %>
References here:
Simple Form collection_check_boxes
Rails collection_check_boxes
This should send the data you require back to your controller. Notice the f.___ -- this tells Rails to build a form using the FormBuilder you've invoked around #leadallocations.
Simply, this means that your data will be encapsulated in the {"leadallocations" => ...} params, whereas if you just use check_box_tag, it will assume the data is independent.
Also, never use HTML to stylize your page. The use of <br> and <table> should only be for formatting. CSS is the only way to stylize your application. Your use of <table> seems to be okay; I just wanted to highlight because most people don't get the idea of HTML vs CSS.
Furthermore, there is another problem - with your associations:
class Leadallocation < ActiveRecord::Base
belongs_to :company
end
You cannot assign multiple company ID's to a belongs_to relationship:
I've seen instances where [foreign_key]_ids can be passed, but it's not recommended; indeed, an antipattern.
What you'll be looking for is has_and_belongs_to_many:
#app/models/leadallocation.rb
class LeadAllocation < ActiveRecord::Base
has_and_belongs_to_many :company
end
#app/models/company.rb
class Company < ActiveRecord::Base
has_and_belongs_to_many :leadallocations
end
#join table - companies_leadallocations
This will definitely permit you associate multiple leadallocations per company and vice versa.
Related
Few years ago I develop aps in Rails 4 and now many things change.
I user Shire GEM in this example to upload photos:
Ok, my models:
Photo model:
class Photo < ApplicationRecord
include ImageUploader::Attachment(:image)
belongs_to :user
end
User model ( i put only few lines):
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one :profile, :dependent => :destroy
has_many :photos, :dependent => :destroy
end
PhotosController:
class PhotosController < ApplicationController
before_action :set_photo, only: %i[ show edit update destroy ]
before_action :authenticate_user!
def create
#photo = Photo.new(photo_params)
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: "Photo was successfully created." }
format.json { render :show, status: :created, location: #photo }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_photo
#photo = Photo.find(params[:id])
end
# Only allow a list of trusted parameters through.
def photo_params
params.require(:photo).permit(:title, :image_data, :image, :user_id)
end
end
UsersController:
class UsersController < ApplicationController
private
# Only allow a list of trusted parameters through.
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:id)
end
end
And now last thing, form for add photos in view:
<%= form_with(model: photo) do |form| %>
<% if photo.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(photo.errors.count, "error") %> prohibited this photo from being saved:</h2>
<ul>
<% photo.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :image %>
<%= form.file_field :image %>
</div>
<%= current_user.id %> // SHOWS USER ID
//// THIS GENERATE ERROR ////
<%#= form.hidden_field :user_id => current_user.id %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
And where I have problem. When I to it in that way I see in logs unpermited parameters :user_id.
But when I submit form I see error "User must exist".
I found solution and change in PhotosController this line:
def create
#photo = Photo.new(photo_params)
to:
def create
#photo = current_user.photos.new(photo_params)
and it start working. Photo have user_id in table. But I want to know why I can't add user_id for photos in form in view like:
<%= form.hidden_field :user_id => current_user.id %>
Never pass the user id as plaintext through the parameters. Get it from the session instead. Its trivial for any malicous user to use the web inspector and simply fill in the hidden input and then upload a unseemly picture as ANY user.
The session cookie is encrypted and much more difficult to tamper with.
class PhotosController < ApplicationController
before_action :authenticate_user!
def create
# build the record off the current_user
#photo = current_user.photos.new(photo_params)
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: "Photo was successfully created." }
format.json { render :show, status: :created, location: #photo }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
private
# Only allow a list of trusted parameters through.
def photo_params
params.require(:photo).permit(:title, :image_data, :image)
end
end
But I want to know why I can't add user_id for photos in form in view like:
<%= form.hidden_field :user_id => current_user.id %>
Because you're calling the method with the wrong arguments. The signature is hidden_field(object_name, method, options = {}) but as already stated its a bad idea.
For my project I am trying to build a dashboard whereby an Agent can view submissions posted by a user and add a Status & Notes to each submission in order to log their own personal activity i.e they would not be changing the actual record, just leaving private notes against it. In order to do this I have created a join table with both Agent id and Submission id as well as Status and Notes columns.
I have managed to create an index view that shows submissions data with 2 form fields at the end of each line from my join table which are called Status and Notes... the problem is when I update these fields they do not get saved to my jointable.
Form on index view
<%= form_with(model: submission, local: true) do |form| %>
<% form.fields_for :agent_activities do |act| %>
<td> <div class="field">
<%= act.text_field :Status %>
</div>
</td>
<td> <div class="field">
<%= act.text_field :Notes %>
</div>
</td>
<td>
<div class="actions">
<%= form.submit %>
</div>
</td>
<% end %>
<% end %>
Model associations in rb files
class Submission < ApplicationRecord
belongs_to :user, :optional => true
belongs_to :location, :optional => true
has_many :agent_activities
end
class AgentActivity < ApplicationRecord
belongs_to :submission, :optional => true #has submission_id
foreign key in table
belongs_to :agent, :optional => true #has agent_id foreign key in
table
end
Controller:
class SubmissionsController < ApplicationController
before_action :set_submission, only: [:show, :edit, :update, :destroy]
def index
#submissions = Submission.where(:user_id => current_user.id)
end
def show
end
def new
#submission = Submission.new
end
def edit
end
# POST /submissions
# POST /submissions.json
def create
#submission = Submission.new(submission_params.merge(user_id: current_user.id))
respond_to do |format|
if #submission.save
# Tell the UserMailer to send a welcome email after save
NewSubmissionMailer.submission_email(#submission).deliver_now
NewSubmissionMailer.matching_agents_email(#submission).deliver_now
format.html { redirect_to #submission, notice: 'Submission was successfully created.' }
format.json { render :show, status: :created, location: #submission }
else
format.html { render :new }
format.json { render json: #submission.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /submissions/1
# PATCH/PUT /submissions/1.json
def update
respond_to do |format|
if #submission.update(submission_params)
format.html { redirect_to #submission, notice: 'Submission was successfully updated.' }
format.json { render :show, status: :ok, location: #submission }
else
format.html { render :edit }
format.json { render json: #submission.errors, status: :unprocessable_entity }
end
end
end
# DELETE /submissions/1
# DELETE /submissions/1.json
def destroy
#submission.destroy
respond_to do |format|
format.html { redirect_to submissions_url, notice: 'Submission was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_submission
#submission = Submission.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def submission_params
params.require(:submission).permit(:First_Name, :Last_Name, :Phone, :Email, :Desired_Location, :number_of_beds, :number_of_occupants, :Rent_price_per_month_gbp, :Max_move_in_date, :Tenant_Occupation, :Contact_me_on, :Furnished, :Current_Address, :Property_Requirements)
end
end
Not sure what im missing here :/
UPDATE BASED OFF #TOM ANSWER
New controller params:
def submission_params
params.require(:submission).permit(:First_Name, :Last_Name, :Phone, :Email, :Desired_Location, :number_of_beds, :number_of_occupants, :Rent_price_per_month_gbp, :Max_move_in_date, :Tenant_Occupation, :Contact_me_on, :Furnished, :Current_Address, :Property_Requirements, agent_activities_attributes: [:id, :Status, :Notes, :_destroy])
end
end
New Submission Model rb:
class Submission < ApplicationRecord
belongs_to :user, :optional => true
belongs_to :location, :optional => true
has_many :agent_activities
accepts_nested_attributes_for :agent_activities
end
Index.html.erb
<%= form_with(model: submission, local: true) do |form| %>
<% form.fields_for :agent_activities, #submission.agent_activities.build do |act| %>
<td> <div class="field">
<%= act.text_field :Status %>
</div>
</td>
<td> <div class="field">
<%= act.text_field :Notes %>
</div>
</td>
<td>
<div class="actions">
<%= form.submit %>
</div>
</td>
<% end %>
On your Submission model add: accepts_nested_attributes_for :agent_activities (accepts_nested_attributes_for documentation) This will let Rails know that your form is going to be supplying fields for an associated model.
Once that is added Rails will be supplying a key in params agent_activities_attributes in your strong params we can add: .permit(..., agent_activities_attributes: [:id, :Status, :Notes, :_destroy]. The :_destroy key is only needed if you plan on having allow_destroy: true on the nested attribute call.
One side note: Capitalized names (Status, Notes, etc) are normally reserved for constants in Ruby. You may want to look into changing your attribute column names to lowercase.
I'm new to Rails and working on a sample app. The idea behind the app is that it's a computerized check-in sheet for kids to ride a school bus. There are four models: Family, Kid, SchoolRide, and HomeRide. For Family and Kid, I generated complete scaffolds, but for SchoolRide and HomeRide, they're just models with a boolean field each of whether the kid has checked in to the schoolbus in the morning or checked out in the afternoon when coming home.
I want to be able to have a user check in a kid from a form rendered on the kid show view, but I'm having trouble creating instances of my ride models from the kids controller. How do I set up the views, routing, and controllers? Where/how do I pass in the parameters to the ride models in the kids controller?
Here's my form rendered into the kid's show view. Currently, I'm getting a syntax error.
<%= form_with(model: #school_ride, remote: true), :url => school_rides_path, :html => { :method => :post } do |form| %>
<div><p>
<%= form.label :check_in %><br>
<%= form.check_box :check_in %><br>
</p>
</div>
<div>
<%= form.hidden_field :kid_id, value: #kid.id %>
</div>
<p>
<%= form.submit %>
</p>
<% end %>
Here're my models:
class Kid < ApplicationRecord
belongs_to :family
has_many :school_rides
has_many :home_rides
end
class HomeRide < ApplicationRecord
belongs_to :kid
end
class SchoolRide < ApplicationRecord
belongs_to :kid
end
Here are some relevant parts of my kids controller:
def show
#family = Family.all
#school_ride = SchoolRide.new
end
# GET /kids/new
def new
#kid = Kid.new
end
# GET /kids/1/edit
def edit
end
# POST /kids
# POST /kids.json
def create
#kid = Kid.new(kid_params)
respond_to do |format|
if #kid.save
format.html { redirect_to family_path(id: #kid.family_id), notice: 'Kid was successfully created.' }
format.json { render :show, status: :created, location: #kid }
else
format.html { render :new }
format.json { render json: #kid.errors, status: :unprocessable_entity }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_kid
#kid = Kid.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def kid_params
params.require(:kid).permit(:name, :birthdate, :grade, :family_id)
end
def school_ride_params
params.require(:school_ride).permit(:check_in)
end
Here's some of my routing:
resources :kids
resources :school_rides, only: [:new, :create]
Try this:
<%=form_for #school_rid, remote: true do |form| %>
I have a order show page shown below. I had this working but ever since I changed computers to work on this app, the name did not display.
If I change <%= #order.user.name %> to <%= #order.user.id %>, I get the correct id. Otherwise I get nothing displaying where as the name of the id should be posted.
#view/orders/show.html.erb
<p>
<strong>Code:</strong>
<%= #order.code %>
</p>
<p>
<strong>Client:</strong>
<%= #order.client.name %>
</p>
<p>
<strong>User:</strong>
<%= #order.user.name %>
</p>
<p>
<strong>Notes:</strong>
<%= #order.memo %>
</p>
<p>
<strong>Status:</strong>
<%= #order.status ? "Confirmed" : "In Progress" %>
</p>
<%= link_to 'Edit', edit_order_path(#order) %> |
<%= link_to 'Back', orders_path %>
#models/order.rb snippet
class Order < ActiveRecord::Base
belongs_to :user
end
#model/user.rb
class User < ActiveRecord::Base
has_many :orders, dependent: :destroy
has_many :addresses, dependent: :destroy
has_many :telephones, dependent: :destroy
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :manager, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
end
#controllers/order_controller.rb snippet
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
I think I just answered another question of yours, but I would recommend using the .delegate method like this:
#app/models/order.rb
Class Order < ActiveRecord::Base
belongs_to :user
delegate :name, to: :user, prefix: true #-> #order.user_name
end
You can delegate multiple variables if you need to.
This fixes Law of Dementer, as described here
As mentioned in comments, the value for the user name is empty and that is why it displays a blank when looking for the name.
Adding a name(string) to the user.name will solve the issue
When using a different database, make sure to also update the database with data, preferably the same data which initially tested with.
It's completely independent of the machine you use, so there have to be some changes you've made in your code that you don't remember.
Check what value is returned when you call this user from the console. Type rails c in the terminal and then type a command:
User.find(<<ID_OF_USER_WHOES_NAME_IS_NOT_DISPLAYED>>).name
If its name is empty, it could be a problem with creating a user or something.
Make update when you'll check it.
I am in the process of creating a forum using Ruby on Rails (I'm pretty new at this) and have managed to get myself utterly stuck.
**Version Ruby on Rails 4.0 **
A forum software can have many Categories, and within these Categories you can have multiple forums.
The main page would look similar to this:
Category 1
Forum 1
Forum 2
Category 2
Forum 3
Forum 4
Forum 5
When you create a forum, you should have a drop down menu that allows you to select which category you wish to place it in.
At first I created two different scaffolds- One for Categories and one for Forums. I used a foreign key to connect the two. I do not know if this is the best method, but I could not get them to interact at all. I ended up screwing up my code so badly I have very little to show for it.
I tried using Adding Sub-categories in Rails4 and categories and sub-categories model rails for solutions but both ended up causing errors.
Here is some of my code. It's not much, but maybe you can tell me where to even begin. If there is a better way of doing this (not using two tables), let me know. I would love to hear the best possible way of doing this without using gems
WARNING: my code is an utter mess.
Migration
class AddForeignToForums < ActiveRecord::Migration
def change
add_column :forums, :category_id, :integer
end
end
Forum Controller (I know I am missing something that will allow me to connect to the Category, I just don't know what)
class ForumsController < ApplicationController
before_action :set_forum, only: [:show, :edit, :update, :destroy]
# GET function. view/forums/index.html.erb
def index
#forums = Forum.all
end
# GET /forums/1. view/forums/show.html.erb
def show
#forum = Forum.find(params[:id])
end
# GET /forums/new. view/forums/new.html.erb
# Be able to list all the Categories.
def new
#forum = Forum.new
#categories = Category.all
end
# GET /forums/1/edit
# Be able to list all the categories.
def edit
#forum = Forum.find(params[:id])
#categories = Category.all
end
# POST /forums
# Allows the creation of a new forum
# Lindsey note: how to save category_idea. Assign to category.
def create
#forum = Forum.new(forum_params)
respond_to do |format|
if #forum.save
#forum = Forum.new(:name => params[:forum][:name],
:category_id => params[:forum][:category_id])
format.html { redirect_to #forum, notice: 'Forum was successfully created.' }
format.json { render action: 'show', status: :created, location: #forum }
else
format.html { render action: 'new' }
format.json { render json: #forum.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /forums/1
# Allows the update of forums.
def update
respond_to do |format|
if #forum.update(forum_params)
format.html { redirect_to #forum, notice: 'Forum was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #forum.errors, status: :unprocessable_entity }
end
end
end
# DELETE /forums/1
def destroy
#forum.destroy
respond_to do |format|
format.html { redirect_to forums_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_forum
#forum = Forum.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def forum_params
params.require(:forum).permit(:name, :description, :category_id)
end
end
Forum Model
class Forum < ActiveRecord::Base
belongs_to :category
end
Category Model
class Category < ActiveRecord::Base
has_many :forums, :dependent => :destroy,
end
Category Index.html.erb
<tbody>
<% #categories.each do |category| %>
<tr>
<td><%= link_to category.name, category %></td>
<td><%= link_to ' (Edit', edit_category_path(category) %></td>
<td><%= link_to '| Destroy)', category, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% category.forums.each do |forum| %>
<tr>
<td><li><%= link_to forum.name, forum %></li></td>
</tr>
<% end %>
<% end %>
</tbody>
Forum _form.html.erb
<%= form_for(#forum) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<%= f.label :category_id %><br />
<%= f.select :category_id, Category.all.map{|c| [c.name, c.id]} %>
<div class="actions">
<%= f.submit %>
</div>
You probably want a table for forums, a table for categories, and a join table that includes a forum_id and category_id - name this forum_categories
class Forum < ActiveRecord::Base
has_many :forum_categories
has_many :categories, :through => :forum_categories
end
And, with categories, you'll do the reverse
class Categories < ActiveRecord::Base
has_many :forum_categories
has_many :forums, :through => :forum_categories
end
For adding categories in the view, you can use checkboxes or a multiple select box. The name of this input will be either
f.check_box 'category_ids[]'
or
f.select 'category_ids[]'
This will submit a param in an array format that will allow you to update the forum.category_ids with a simple
forum.create(params[:forum])
In your view, instead of #forums, you'll list category.forums
<% category.forums.each do |forum| %>
<%= forum.name %>
<% end %>
Hopefully this will get you started.
EDIT
For a single category on Forum, you've done well. Just a few smaller changes:
class Category < ActiveRecord::Base
# belongs_to :category - this can be removed
has_many :forums # Do you want to delete the forums if the category is removed? You don't need the classname option.
end
In the drop down - you'll do something like this...
f.select :category_id, Category.all.map{|c| [c.name, c.id]}