i'm trying to Add Categories to my Rails app, but don't quite know how to do this.
I have many Pins(Images) and want the user to be able to assign a category on those Pins.
ASSIGN not create, edit, or delete a Category, just selecting one for their Pin.
Meaning that, When a user uploads a pin, he can choose from a dropdown list a Category.
Then, another user can choose from the Menu a Category, and ONLY the Pins in this Category will be listed.
How do i do this? Where to start ?
Thank you
First If you don't want to manage categories in your application, then you can simply add a category field in your table and category select in your application :
<%= f.select :category, [ 'Box', 'Cover', 'Poster' ], :prompt => 'Select One' %>
Second, If you want to manage categories in your application, than you have to maintain a separate model and table for it. So you can start with generating your model:
rails g model category
it will add model and migration in your application directory. Add stuff to your migration:
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.text :description
## you can add more stuff as per your requirements
t.timestamps
end
end
end
Define associations in category & Pin model add validation for this :-
In Category Model:
has_many :pins
In Pin Model :
belongs_to :category
validates :category, presence: true
Create some categories by categories controller and form (I don't think, I need to tell you that stuff, you are able to do it yourself)
In your pin uploading form add this select :-
<%= f.select :category, Category.all, :prompt => "Select One" %>
Hope, It will help.
you might wanna add a def to_s method on your Category model. I believe it will display some weird memory address code just by using plain Category.all on the f.select option. Everything else looks great!
Related
I want the users to be able to write down their skills as hashtags in a text_field. I already can store a string and split it up like (btw: a user has one account)
<% #user.account.hashtag.split('#').reject { |c| c.empty? }.each do |d| %>
<p><%= d %></p>
<% end %>
But that is not elegant as it's processed in the view right now and since its just one string which is displayed as an array, I cant iterate. What I want to achieve is explained in this video.
A user should write down his skills in one field, the string should be split up at every '#' symbol and stored in a field which should belong to the user, so I can do something like url.com/user/hashtag/xyz while xyz is the hashtag.
The video tutorial is made well, but it does not work for rails 5+ since find_by is not available anymore; also I don't want to create some new tables, because later I want to do the same with other models than account. Later I want to add a autocomplete function in a search field via gems like select2. That is why it might help to add another table for the tags? :S
thanks in advance!
so there are lots of things in this short question.
The first thing that I would do would be to create a hashtag table
class CreateHashtags < ActiveRecord::Migration[5.0]
def change
create_table :hashtags do |t|
t.string :hashtag
t.references :hashtagsable, polymorphic: true
t.timestamps null: false
end
end
end
This line is critical
t.references :hashtagsable, polymorphic: true
This will create 2 new field
:hashtagsable_type => :string, # This reference the model of the assiciation
:hashtagsable_id => :integer, # This reference the id of the assiciation
This new model should look like
# app/models/hashtag.rb
class Hashtag < ApplicationRecord
belongs_to :hashtagsable, polymorphic: true
end
Now your user model you should add this line
class User < ApplicationRecord
has_many :hashtags, as: :hashtagsable # User.last.hashtags
end
class Account < ApplicationRecord
has_many :hashtags, as: :hashtagsable # Account.last.hashtags
end
in your view should look like
<% #user.account.hashtags.each do |hashtag| %>
<p><%= hashtags.hashtag %> </p>
<% end %>
I hope that this helps and set you in the right path
I have two models Trip and Attraction for admin panel I have used ActiveAdmin. Now while creating new trip from activeadmin I wished to add user can select multiple Attractions and it's data should be stored in another table called trip_attractions (:trip_id , :attraction_id)
Here is my model:
class Trip < ActiveRecord::Base
has_and_belongs_to :attractions
end
class Attraction < ActiveRecord::Base
has_and_belongs_to_many :trips
end
class TripAttraction < ActiveRecord::Base
has_many :trips
has_many :attractions
end
and for ActiveAdmin form customization I tried in app/admin/trip.rb
ActiveAdmin.register Trip do
.....
form multipart: true do |f|
f.inputs "Trip" do
f.input :title
f.input :description
# Here I want to show all attractions and as multiple select it should be stored in trip_attractions table
f.input 'Attractions' do
f.input :attractions, :as => :select, :multiple => true, collection: Attraction.all
end
end
Where I do mistake? Please guide me how can I show all attractions on new trip form and on multiple select it should be stored in trip_attractions table. I really appreciate for your guideline and help. If you required more details then please feel free to ask.
In addition : I also tried to add attraction_ids field in trip table and in model I defined it as serialize to stored as an array of attraction's ids but I think it's not good approach as attraction may deleted it's id will remain in trip table. So I avoid this option and also not saved in database while submitting form. :(
I'm building a daily deal Rails app to learn RoR.
I am facing a problem for the past few hours : i can't get a model's attribute of an other associated model on active admin. Let me show you exactly the problem :
I have two models: Brand (i.e the brand of the deal) and Deal. A deal belongs to a Brand but a Brand can have many Deals.
models/deal.rb is like this:
class Deal < ActiveRecord::Base
belongs_to :brand
and we have models/brand.rb:
class Brand < ActiveRecord::Base
has_many :deals
attr_accessible :name
And i did the t.belongs_to in my migrations so this is ok.
In Active Admin's Deals' create form , i type, as admin, which brand the deal is associated with:
admin/game.rb
ActiveAdmin.register Deal do
# -- Form -----------------------------------------------------------
form do |f|
f.inputs "Brand (i.e. client)" do
f.input :brand_id, :label => "Select a brand:", :as => :select, :collection => Brand.all
end
it works great, and i can create Deals with a certain brand.
but I CAN'T manage to display the NAME of the Brand in my list of Deals:
ActiveAdmin.register Deal do
index do
selectable_column
# id_column
column :title
column :deal_amount
column :brand do |deal|
link_to deal.brand.name
end
...doesn't work.
How can I do that ?
I tried everything but i basically don't know how to fetch the name of a Brand given it matches the brand_id in the Deal's table.
Any help appreciated.
show do |f|
panel "Subject" do
attributes_table_for f, :name, :description, :is_visible
end
panel "Pages in List View" do
table_for(f.pages) do |page|
column :name
column :permalink
column :is_visible
end
end
panel "Pages in View " do
div_for(f.pages) do |page|
panel page.name do
attributes_table_for page, :name, :description, :is_visible
end
end
end
end
end
You can do nested relations in same style as parent model
A couple things seem missing:
class Deal < ActiveRecord::Base
belongs_to :brands, foreign_key: :brand_id, class_name: 'Brand'
end
This is assuming that you mean partner to be a Brand and your schema uses brand_id for that relationship.
In your form, you can simply use:
form do |f|
f.inputs "Brand (i.e. client)" do
f.input :partner, label: 'Select a brand:'
end
end
Your link_to call won't actually link to a url the way you have it.
column :brand do |deal|
link_to deal.partner.name, admin_brand_path(deal.partner)
# or simpler
auto_link deal.partner
end
I would highly recommend trying to be consistent in your naming, as it will make things a lot less confusing and will require less code to make things work. i.e.
class Deal < ActiveRecord::Base
belongs_to :brand
end
f.input :brand, label: 'Select a brand:'
auto_link deal.brand
And your DB column can still be named brand_id.
I try to learn the has_and_belongs_to_many relationship between my 2 fresh new and simple models Product and Author, where a Product can have many authors and where author can have a lots of products.
I wrote this :
class Author < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :authors
end
In the partial form of view for the products, I have :
<p>Products</p>
<%= collection_select(:product, :author_ids, #authors, :id, :name, :prompt => " ", :multiple => true) %>
but when I hit the update button, I get this strange message I can't resolve myself :
NoMethodError in ProductsController#update
undefined method `reject' for "1":String
Rails.root: /home/stephane/www/HABTM
Application Trace | Framework Trace | Full Trace
app/controllers/products_controller.rb:63:in block in update'
app/controllers/products_controller.rb:62:inupdate'
Request
Parameters:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"2GlTssOFjTVZ9BikrIFgx22cdTOIJuAB70liYhhLf+4=",
"product"=>{"title"=>"Le trésor des Templiers",
"original_title"=>"",
"number"=>"1",
"added_by"=>"",
"author_ids"=>"1"},
"commit"=>"Update Product",
"id"=>"1"}
What's wrong ? Is there a problem with :product_ids... I saw on internet I had to pu a "s" but I'm not sure of what it represents....
How can I link the table authors_products to the key which is given back by the drop-down menu ? (here "author_ids"=>"1")
Thx !
More info :
May be solved with this info, but still no saving of the relationship :
collection_select("sales_agent", "customer_id", #customers, "id", "name")
Assuming you had a customer model with an ID attribute and a name attribute, this would produce exactly the above code. So looking at the values we pass into the collection_select call:
The first parameter is the model that contains one element from the collection (eg. sales_agent)
Next is the field name in the model that refers to the collection element it contains (eg. customer_id)
Next is the variable containing the collection of items that we want to list (eg. #customers)
Next is the value attribute of the option tag (eg. the customer id)
Next is the display attribute of the option tag (eg. the customer name)
So I now wrote
<p>Products</p>
<%= collection_select(:author, :author_id, #authors, :id, :name, :prompt => " ", :multiple => true) %>
and it worked, but without saving the link, for the moment... (only the update of the normal fields are saved, not the relationship :-(
Do you have a separate model called author_products for the HABTM relationship?
You'll need to run another migration by doing something like rails g model author_product and the table should only contain two fields:
belongs_to :author
belongs_to :product
Make sure there is no primary key.
Something like:
def self.up
create_table(:author_products), :id => false do |t|
t.references :author
t.references :product
end
end
In have a pretty simple rails app, here's my code:
class Post < ActiveRecord::Base
belongs_to :category
attr_accessible :category_id, :category_attributes
accepts_nested_attributes_for :category, :reject_if => :all_blank
end
class Category < ActiveRecord::Base
has_many :posts
end
#app/views/posts/_form.html.haml
= simple_form_for(#post) do |f|
= f.association :category
= f.simple_fields_for :category do |cat_f|
= cat_f.input :name
So when creating a new post, I have the option to choose a category (from the select menu) or create a new one (if it doesn't exist).
I want to validate that category_id is present, unless the user opts to create a new category
I'm guessing there's some kind of rails way to solve this problem - I know that I can't just add validates :category_id, :presence => true as this will cause form submission to fail when the user decides to create a new category (and doesn't select one from the drop-down).
Second Question:
I recently read a useful rails tutorial that showed you how to toggle between displaying the category select menu and the new category fields so that only one of the two is present on screen at any given time. Anyone got a link to something like that?
I think I have fixed this by replacing:
validates :category_id, :presence => true
with
validates :category, :presence => true
It seems to work.
Strange one.
PS
I can only imagine that this works because :category is considered present if the user selects something from the drop-down list OR if they create a new category using the nested form, whereas previously, with my original code, :category_id was only considered present when the user selected something from the drop-down and NOT when they created a new record.
In your PostsController, you probably want to check the incoming parameters in your create action to see if category_id is your default value (here, -1), and if so, create a new category from the text field. Something like this:
def create
if params[:post][:category_id] != -1
category = Category.create params[:post][:category_name]
# make sure category is attached to post
end
# rest of your create action
end
And something similar in your update action.
As for your second question, that's probably less Rails and better handled by Javascript. You could pretty easily have a radio button for 'use existing category' or 'create new category', and then use javascript to swap the DOM objects appropriately.