split a string and save it in multiple records - ruby-on-rails

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

Related

Issues with checkboxes updating join table

Theres a lot of stuff around that is similar but nothing actually addresses this particular circumstance. I would like to preface by saying im still new in the Rails world.
So i have a User table and a Skill table and corresponding models.
I have created a join table to connect the 2 and have a HABTM relationship between the 2.
SKILL MODEL
class Skill < ActiveRecord::Base
has_and_belongs_to_many :users
end
USER MODEL
class User < ActiveRecord::Base
has_and_belongs_to_many :skills
end
JOIN TABLE MIGRATION
class CreateJoinTableSkillsUsers < ActiveRecord::Migration
def change
create_join_table :skills, :users do |t|
t.index [:skill_id, :user_id]
t.index [:user_id, :skill_id]
end
end
end
ADDSKILL METHOD (In skills controller)
def addSkill
#user.id = current_user.id
#skill.id = Skill.find(params[:id])
params[:user_id, :skill_id]
redirect_to user_path
end
RELEVANT ROUTE?
put 'skills/addSkill' => 'skills#addSkill'
index.html.erb (skills)
<% commerceCategory.each do |skill| %>
<ul>
<%= button_to skill.title, :method => "addSkill" %>
</ul>
<% end %>
Submit Button
<%= submit_tag "Update Skills"%>
So basically i want:
a) skill.title to be a checkbox of itself (the name within the checkbox not one alongside it)
b)once its clicked, it will assign that particular skill to the current_user.id via the join table and redirect to the users show page to show the skills that user has.
I have tried so many different things and i cant seem to make it work.
Ive read all over that the has many through is a preferential association especially since i will be wanting to add varying degrees of skill for each skill eventually.
Any guidance would be greatly appreciated!

how to associate two models using has_many and belongs_to ruby on rails

I have generated two models tour and tourcategories in my application. Now I want to associate these two models using has_many and belongs_to. Where tour can relate with single tourcategory but tourcategory can have more than one tours. So definition of the tour model is following:
class Tour < ActiveRecord::Base
belongs_to :tourcategory
attr_accessible :content, :element_id, :job_id, :title, :priority, :tourcategory
end
this is the definition of tourcategory model:
class Tourcategory < ActiveRecord::Base
has_many :tours
attr_accessible :title
end
this is the definition of the tours migration file:
class CreateTours < ActiveRecord::Migration
def change
create_table :tours do |t|
t.string :element_id
t.string :title
t.text :content
t.integer :job_id
t.integer :priority
t.belongs_to :tourcategory, index:true
t.timestamps
end
end
end
this is the definition of the tours controller :
def new
#tourcategories = Tourcategory.all
#tour = Tour.new
#tour.build_tour
respond_to do |format|
format.html
format.json { render json: #tour }
end
end
Now I am getting an error
undefined method `tourcategories'
When I access the _form.html.haml view for editing and for adding new tour.
this the code where error is encountered.
.field
= label_tag "tour Categories"
%br/
= select_tag "tourcategory", options_from_collection_for_select(Tourcategory.all, 'id', 'title', #tour.tourcategories.map{ |j| j.id })
= f.submit
You defined,
Tourcategory has multiple tours. has_many :tours
Tour belongs to one Tourcategory. belongs_to :tourcategory
So, you can not call tourcategories from #tour. you can call tourcategory from #tour
Additionaly,
#tour.build_tour <- makes error maybe.
you can use build_* method for belongs_to relation.
I think you should try #tour.build_tourcategory
Read "Action Record Association" section in Rails Guide: http://guides.rubyonrails.org/association_basics.html
You can't call #tour.tourcategories, because a Tour belongs to a single Tourcategory, so that method wouldn't be generated by Rails. You may call #tour.tourcategory or #tourcategory.tours.
Why are you passing a fourth argument to options_for_collection_from_select anyway? That map method will return a collection, but you want an element. Try omitting it and see if it works.
A couple more issues with your code:
#tour.build_tour won't work unless you have explicitly defined that method (and if you have, it might be better to name it something else). All build_something methods are generated for has_one relationships. Maybe you're looking for #tourcategory.tours.build.
You shouldn't call Tourcategory.all from your view, instead use the #tourcategories variable you defined in the controller. Views should never call models directly.
If you're using Rails 4, you shouldn't be using attr_accessible, but rather define strong parameters in the controller.
Hope that helps.
You actually need to use HABTM (Has And Belongs To Many) - please check out Rails documentation for more details

How can I synchronize a has_many association using accepts_nested_attributes_for by foreign_key instead of ID?

I would like to synchronize a has_many association by foreign key. It seems I have to write custom code to do this. Is there any Rails / Active Record magic / Gem to achieve this? Specifically, I'd like to synchronize a join-table where the pairs of foreign keys should be unique.
class Food < ActiveRecord::Base
has_many :food_tags, :dependent=>:destroy, :inverse_of => :food
accepts_nested_attributes_for :food_tags, :allow_destroy => true
end
class FoodTag < ActiveRecord::Base
belongs_to :tag, :inverse_of=>:food_tags
belongs_to :food, :inverse_of=>:food_tags
end
class Tag < ActiveRecord::Base
has_many :food_tags, :dependent=>:destroy, :inverse_of=>:tag
has_many :foods, :through=>:food_tags
end
For my form with nested attributes (or my JSON API), I'd really like to omit the FoodTag id and use the tag_id to synchronize when updating a food.
I want to submit this on update to show that the tag is set or cleared
# this one is set
food[food_tag_attributes][0][tag_id] = 2114
food[food_tag_attributes][0][_destroy] = false
# this one is cleared
food[food_tag_attributes][1][tag_id] = 2116
food[food_tag_attributes][1][_destroy] = true
Instead, I have to submit this for update:
# this one is set
food[food_tag_attributes][0][id] = 109293
food[food_tag_attributes][0][tag_id] = 2114
food[food_tag_attributes][0][_destroy] = false
# this one is cleared
food[food_tag_attributes][0][id] = 109294
food[food_tag_attributes][1][tag_id] = 2116
food[food_tag_attributes][1][_destroy] = true
This pushes a burden to the client to know the IDs of the food tag records instead of just being able to Set or Clear tags based on the tag id.
Can this be done easily? I'm sure I could write a before_save filter on Food, but it seems like there should be a reasonably generic solution.
There is an option called index: for fields_for in the view helper. You can set the index as your foreign_key. Then instead of sequential or some arbitrary numbers, your foreign_key will be used as the key to refer to your object.
EDIT:
<%= form_for #person do |person_form| %>
<%= person_form.text_field :name %>
<% #person.addresses.each do |address| %>
<%= person_form.fields_for address, **index**: address.id do |address_form|%>
<%= address_form.text_field :city %>
<% end %>
<% end %>
<% end %>

How to include an array into params for model backed form

I have a complex model backed form and want to include multiple objects into my params.
My setup:
Network.rb
class Network < ActiveRecord::Base # t.string "name"
has_many :trackings
has_many :installations, through: :trackings
end
Installation.rb
class Installation < ActiveRecord::Base # t.string "name"
has_many :trackings
has_many :networks, through: :trackings
end
Tracking.rb
class Tracking < ActiveRecord::Base # t.string "code
belongs_to :network # t.integer "network_id",
belongs_to :installation # t.integer "installation_id
end
When I create a new Tracking-Object, I want to render each Network in the database and add a textfield for :code
My form:
= form_for [:admin, #tracking] do |f|
= f.select :installation_id, options_for_select(Installation.all.map { |i| [i.name, i.id] }), prompt: "Select an Installation"
- Network.all.each do |network|
= f.text_field :code
= f.submit
Currently all text fields get rendered but when I submit, only the last input of the last text field gets into my params. How can I include ALL of them?
For non model-backed form I found this, but it's not working for my form:
= text_field_tag "tracking[][code]"
The problem is that all form fields in each iteration of network have the same name so they're all mapped to the same position on your input hash... which is why you only see the last entry.
If you do...
=text_field_tag "admin[][code[][#{network_id}]]"
... you'll get code returned as a hash with network_id as the key, and user input as the value. So you'll get separate values that you can manipulate.
The problem is that when a view gets rendered, it all gets translated into a format suitable for an HTML PUT, which does not support arrays. You'll need to assign a different name to each code field, perhaps appending the array index to the end of each one after a delimiter (:code-2 for example). Each value will then have it's own parameter. When the form gets posted, you can split the names using the delimiter to find those that start with post, and get the array index back so you can assign it to the array again.

Has Many: though relationship problems. Submitting forms

I am trying to have a many to many relationship between players and fixtures. So when a player has played in a fixture I can see what fixtures the players have played in and who has played in the fixtures.
I am trying to then track if the player has paid for the game using a "sub_paid" column with boolean. I am having a hard time setting this to true or false. I can create a player/fixture record but not have a sub_paid attribute.
Models
class Fixture < ActiveRecord::Base
has_many :player_fixtures
has_many :players, :through => :player_fixtures
class Player < ActiveRecord::Base
has_many :player_fixtures
has_many :fixtures, :through => :player_fixtures
class PlayerFixture < ActiveRecord::Base
belongs_to :player
belongs_to :fixture
Migrations
class CreatePlayerFixtures < ActiveRecord::Migration
def change
create_table :player_fixtures do |t|
t.integer "player_id"
t.integer "fixture_id"
t.boolean "sub_paid"
t.timestamps
end
Controller
Not sure what to put here as I have none specificity one for player_fixture
View
I have this at the moment.
<%=form_for(#fixtures, :url => {:action =>'create'}) do |f| %>
questions
Could someone point me in the right direction!
My big questions that I am really stuck on at the moment.
Saving this to the database with sub_paid = false when form is first submitted then being able to change this at a later date to true.
Being able to sort all players by sub_paid = false on a fixture view. EG on my player list sort them so it only shows false.
I have another question here that is still un answered about forms and checkboxes. HABTM Form not submitting more than one value in rails
I understand this is alot but this is for a project I am doing and have been looking at a screen trying everything for 3 weeks now. I need to get this done.
Try adding the following to your form:
<%= check_box_tag :sub_paid %>
<%= select_tag :player_id, options_for_select(Player.all.map{|p| [p.name, p.id] %>
Note that these are ordinary check_box_tag and select_tag and not f.check_box or f.select. We don't want these parameters to be in your :fixture parameter. Now the create action in your FixtureController should look something like this:
def create
#fixture = Fixture.new(params[:fixture])
if #fixture.save
#player = Player.find(params[:player_id])
#fixture.player_fixtures << PlayerFixture.new(:sub_paid => params[:sub_paid], :player => #player)
# other stuff, redirect, etc.
else
# error handling, render, etc.
end
end
You should probably do some checks to make sure the PlayerFixture saving part goes well, but you get the idea. Hope that helps or at least gives you some ideas.

Resources