I have successfully implemented the dynamic select menus for city and area models in my app.
now I have the following models:
class Pet < ActiveRecord::Base
belongs_to :pet_type
belongs_to :pet_category
belongs_to :pet_breed
end
class PetType < ActiveRecord::Base
has_many :pet_categories, through: :pet_type_categories
has_many :pet_type_categories
end
class PetCategory < ActiveRecord::Base
has_many :pet_types, through: :pet_type_categories
has_one :pet_type_category
end
class PetTypeCategory < ActiveRecord::Base
belongs_to :pet_type
belongs_to :pet_category
has_many :pet_breeds
end
class PetBreed < ActiveRecord::Base
belongs_to :pet_type_category
belongs_to :pet_Type
belongs_to :pet_category
end
migrations:
class CreatePetTypes < ActiveRecord::Migration
def change
create_table :pet_types do |t|
t.string :name
t.timestamps
end
end
end
class CreatePetCategories < ActiveRecord::Migration
def change
create_table :pet_categories do |t|
t.string :name
t.timestamps
end
end
end
class CreatePetTypeCategories < ActiveRecord::Migration
def change
create_table :pet_type_categories do |t|
t.references :pet_type, index: true
t.references :pet_category, index: true
t.timestamps
end
end
end
class CreatePetBreeds < ActiveRecord::Migration
def change
create_table :pet_breeds do |t|
t.string :name
t.references :pet_type_category, index: true
t.timestamps
end
end
end
The pet_type_category table is a join table for pet_types that share the same pet_categories.
So my question is how do I create 3 dynamic select menus of pet_type, pet_category and pet_breed in the create form?
Thanks
Edit: I managed to get the pet type collection_select and pet category grouped_collection_select done once I updated the relationships, now the 3rd one (pet breed) is what I'm stuck at..
I understand now after a bit of a research that it is not possible to have nested groups though surely It should be possible using some kind of helper, however for a lack of a better solution, I added to the PetTypeCategory model:
def pet_type_category_names
"#{self.pet_type.name} #{self.pet_category.name}"
end
and in my view now I have:
<div class="field">
<%= f.collection_select :pet_type_id, PetType.all, :id, :name, {prompt: "Choose your pet's type"} %>
</div>
<div class="field">
<%= f.grouped_collection_select :pet_category_id, PetType.all, :pet_categories, :name, :id, :name, {prompt: "Choose your pet's category"} %>
</div>
<div class="field">
<%= f.grouped_collection_select :pet_breed_id, PetTypeCategory.all, :pet_breeds, :pet_type_category_names, :id, :name, {prompt: "Choose your pet's breed"} %>
</div>
so for the 3rd select instead of having:
Dog
Small
Breed
I have:
Dog Small
Breed
Related
I am new to Rails and working on a blog project.
I have articles and categories. Each article can have multiple categories and each category can belong to multiple articles.
I also have a join table articles_categories
My migrations:
class CreateArticles < ActiveRecord::Migration[5.2]
def change
create_table :articles do |t|
t.string :title
t.text :body
t.timestamps
end
end
end
class CreateCategories < ActiveRecord::Migration[5.2]
def change
create_table :categories do |t|
t.string :name
t.timestamps
end
end
end
class CreateArticlesCategoriesJoinTable < ActiveRecord::Migration[5.2]
def change
create_join_table :articles, :categories do |t|
t.index :article_id
t.index :category_id
end
end
end
My model associations:
class Article < ApplicationRecord
has_and_belongs_to_many :categories
end
class Category < ApplicationRecord
has_and_belongs_to_many :articles
end
This all makes sense so far.
What I am struggling with now, is how do I add categories when creating a new Article? I want to be able to select pre-defined categories from a list (stored in Category table) through a form.
What model and/or URL (if any) do I use in the form_with helper?
Is the following anywhere close?
<% form_with model: ???, url: ??? do |f| %>
<%= f.collection_select :category_id, Category.order(:name), :id, :name %>
<% end %>
I have many images(add_images_to_steps) belonging to steps which belongs to diys. All information saves correctly as DB browser shows, but i have problem viewing images.
with
views/diys/show.html.erb
<p id="notice"><%= notice %></p>
<h2><%= #diy.summary %></h2>
<% #steps.each do |step| %>
<p><%= step.step_content %></p>
<% step.add_images_to_steps.each do |i| %>
<%= image_tag i.image_url.to_s %>
<% end %>
<% end %>
I get NoMethodError in Diys#Show
undefined method `image_url' for #
and if I change
to
I get this
-----------------------------------------------------------------------
Heres My migrations, models and controllers.
-----------------------------------------------------------------------
diys_controller.rb
class DiysController < ApplicationController
before_action :set_diy, only: [:show, :edit, :update, :destroy]
def show
#diy = Diy.find(params[:id])
#steps = #diy.steps.all
#diy.add_images_to_steps.all
end
def new
#diy = Diy.new
#step = #diy.steps.new
#step.add_images_to_steps.new
end
...
def diy_params
params.require(:diy).permit(:title, :summary, :tip, :warning, steps_attributes: [:step_content, add_images_to_steps_attributes: [:image]])
end
models/diy.rb
class Diy < ActiveRecord::Base
has_many :steps, dependent: :destroy
accepts_nested_attributes_for :steps, reject_if: :all_blank
has_many :add_images_to_steps, :through => :steps, dependent: :destroy
accepts_nested_attributes_for :add_images_to_steps
end
models/step.rb
class Step < ActiveRecord::Base
belongs_to :diy
has_many :add_images_to_steps, dependent: :destroy
accepts_nested_attributes_for :add_images_to_steps
mount_uploader :image, ImageUploader
end
models/add_images_to_step.rb
class AddImagesToStep < ActiveRecord::Base
belongs_to :step
end
Diy migration
class CreateDiys < ActiveRecord::Migration
def change
create_table :diys do |t|
t.string :title
t.text :summary
t.text :tip
t.text :warning
t.timestamps null: false
end
end
end
Steps migration
class CreateSteps < ActiveRecord::Migration
def change
create_table :steps do |t|
t.belongs_to :diy
t.text :step_content
t.timestamps null: false
end
end
end
add_images_to_step migration
class CreateAddImagesToSteps < ActiveRecord::Migration
def change
create_table :add_images_to_steps do |t|
t.belongs_to :step
t.string :image
t.timestamps null: false
end
end
end
I figured it out!!
Had to add
mount_uploader :image, ImageUploader
to ../models/add_images_to_step.rb
change def store_dir to
"#{Rails.root}/public/uploads/"
in ../app/uploaders/image_uploader.rb
and
"<%= image_tag i.image_url.to_s %>"
was right for show view.
I'm very new to ruby on rails. Thanks for your patience in advance.
<div class="field">
<%= #pin.image_url if #pin.image? %>
<%= f.file_field :image %>
<%= f.hidden_field :image_cache %>
</div>
What does #pin.image? do?
There is not image? method in my controller. I'm guessing it's one of the helper functions provided by rails for every controller? Is that right?
What is f ?
here is my model for pin
class Pin < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
belongs_to :board
end
and its schema
class CreatePins < ActiveRecord::Migration
def change
create_table :pins do |t|
t.string :name
t.string :image
t.integer :board_id
t.timestamps null: false
end
end
end
class AddImageToPins < ActiveRecord::Migration
def change
add_column :pins, :image, :string
end
end
There is not image? method in my controller.
You don't call this method on your controller, but on your object assigned to #pin variable, which is probably your Pin model. And your model does have image? method.
What is f ?
It's the form builder object, passed into form_for block.
Not sure how to delete the associate between 'fly' and 'invoice'. What I've tried so far deletes the fly from the database
<table class="table table-condensed">
<thead>
<tr>
<th>Invoice Flies</th>
</thead>
<tbody>
<% #invoice.flies.each do |fly| %>
<tr>
<td><%= fly.name %></td>
<td><%= link_to "delete", ??????, method: :delete,
data: { confirm: "You sure?" } %></td>
</tr>
<% end %>
</tbody>
</table>
Invoice Model:
class Invoice < ActiveRecord::Base
attr_accessible :active
validates :user_id, presence: true
belongs_to :user
has_many :categorizations
has_many :flies, through: :categorizations
end
Invoice migration:
class CreateInvoices < ActiveRecord::Migration
def change
create_table :invoices do |t|
t.boolean :active
t.integer :user_id
t.timestamps
end
add_index :invoices, :user_id
end
end
Categorization Model:
class Categorization < ActiveRecord::Base
attr_accessible :fly_id, :user_id
belongs_to :invoice
belongs_to :fly
end
Categorization migration:
class CreateCategorizations < ActiveRecord::Migration
def change
create_table :categorizations do |t|
t.integer :user_id
t.integer :fly_id
t.timestamps
add_index :categorizations, :user_id
add_index :categorizations, :fly_id
end
end
end
Fly Model:
class Fly < ActiveRecord::Base
attr_accessible :description, :name
validates :description, :name, presence: true
has_many :categorizations
has_many :invoices, through: :categorizations
end
Fly migration:
class CreateFlies < ActiveRecord::Migration
def change
create_table :flies do |t|
t.string :name
t.string :description
t.timestamps
end
end
end
You can use dependent: :destroy like this:
class Fly
has_many :categorizations, dependent: :destroy
...
end
This will destroy the categorizations related to that Fly.
Also, remember to use Fly.destroy(:id) (DO NOT USE Fly.delete(:id), or it won't remove the categorizations dependent on that Fly)
I need (or I think) implement polymorphic association in my model but I have something wrong. Let see my situation, it's a simple question/answers system, and the logic is the following:
- a question can be ansewered by N answers.
- An answer can be only a "text" XOR (one or other, not both) a "picture".
Migrations:
class CreateAnswers < ActiveRecord::Migration
def change
create_table :answers do |t|
t.integer :question_id
t.references :answerable, :polymorphic => true
t.timestamps
end
end
end
class CreateAnswerTexts < ActiveRecord::Migration
def change
create_table :answer_texts do |t|
t.text :content
t.timestamps
end
end
end
class CreateAnswerPictures < ActiveRecord::Migration
def change
create_table :answer_pictures do |t|
t.string :content
t.timestamps
end
end
end
Models
*answer.rb*
class Answer < ActiveRecord::Base
belongs_to :user_id
belongs_to :question_id
belongs_to :answerable, :polymorphic => true
attr_accessible :answerable_type
end
answer_text.rb
class AnswerText < ActiveRecord::Base
TYPE = "text"
has_one :answer, :as => :answerable
attr_accessible :content
end
answer_picture.rb
class AnswerPicture < ActiveRecord::Base
TYPE = "picture"
has_one :answer, :as => :answerable
attr_accessible :content
end
Controller
answers_controller.rb:
...
def create
post = params[:answer]
create_answerable(post[:answerable_type], post[:answerable])
#answer = #answerable.answer.new()
end
private
def create_answerable(type, content)
#answerable = ('Answer' + type.capitalize).classify.constantize.new(:content => content)
#answerable.save
end
...
And view form (Only have these fields):
...
<div class="field">
<%= f.label :answerable_type %><br />
<%= select("answer", "answerable_type", Answer::Types, {:include_blank => true}) %>
</div>
<div class="field">
<%= f.label :answerable %><br />
<%= f.text_field :answerable %>
</div>
...
So, the problem is when I submit form I get this error:
undefined method new' for nil:NilClass
app/controllers/answers_controller.rb:52:increate'
Answers? :)
on a has_one relationship, you have to use :
#answerable.build_answer
or
#answerable.create_answer
instead of
#answerable.answer.new
see the reference for more info.