I'm working on a project where Users can see dog Parks and make individual Playdates for each park. The issue I'm having is that the PlaydatesController create action is not persisting the user_id and park_id that each new playdate is associated with. I've tried adding optional: true to my Playdate model, which does save each playdate. However, doing this makes a null column entry for the user_id and park_id.
All I need is the user_id and park_id to create a playdate and keep the association between playdates and parks... Did I mess up my associations? Any help is GREATLY appreciated.
Here's my code:
Playdate MODEL:
class Playdate < ApplicationRecord
belongs_to :park
belongs_to :user
validates :date, presence: true
validates :time, presence: true
end
Park MODEL:
class Park < ApplicationRecord
has_many :playdates
has_many :comments
has_many :users, through: :comments
end
User MODEL:
class User < ApplicationRecord
has_many :parks
has_many :playdates
has_many :comments, through: :parks
end
Playdates CONTROLLER:
def create
#playdate = Playdate.new(playdate_params)
if #playdate.save!
redirect_to park_path(#park)
else
render :new
end
end
private
def playdate_params
params.require(:playdate).permit(:time, :date, :user_id, :park_id)
end
Playdates NEW VIEW:
<%= form_for #playdate do |f| %>
<%= f.label :date %>
<%= f.date_field :date %><br><br>
<%= f.label :time %>
<%= f.time_field :time %><br><br>
<%= hidden_field_tag :user_id, current_user.id %>
<%= hidden_field_tag :park_id, #park%>
<%= f.submit "Add Playdate!" %>
<% end %>
You should use:
f.hidden_field :user_id, value: current_user.id
f.hidden_field :park_id, value: #park.id
The rendered HTML is not the same between "hidden_field_tag" and "hidden_field". Try by yourself to see the difference.
Related
I am trying to make a player character generator. I have a form that hopefully will allow me to attach skills with their values to a character sheet model. I made models like this:
class CharacterSheet < ApplicationRecord
has_many :character_sheet_skills, dependent: :destroy
has_many :skills, through: :character_sheet_skills
belongs_to :user
accepts_nested_attributes_for :skills
end
class Skill < ApplicationRecord
has_many :character_sheet_skills, dependent: :destroy
has_many :character_sheets, through: :character_sheet_skills
attr_reader :value
end
class CharacterSheetSkill < ApplicationRecord
belongs_to :skill
belongs_to :character_sheet
end
Character sheet model holds data about player character and skill model has all skills available in game. In CharacterSheetSkill I'd like to store the skills that the player chooses for his character together with an integer field setting the skill value.
When opening form, I already have a full list of skills in database. All I want to do in form is create a character sheet that has all of these skills with added value. I tried using "fields_for" in form, but I couldn't really get that to work. Right now it looks like this:
<%= simple_form_for [#user, #sheet] do |f| %>
<%= f.input :name %>
<%= f.input :experience, readonly: true, input_html: {'data-target': 'new-character-sheet.exp', class: 'bg-transparent'} %>
...
<%= f.simple_fields_for :skills do |s| %>
<%= s.input :name %>
<%= s.input :value %>
<% end %>
<% end %>
How can I make that form so it saves character sheet together with CharacterSheetSkills?
A better idea here is to use skills as a normalization table where you store the "master" definition of a skill such as the name and the description.
class CharacterSheetSkill < ApplicationRecord
belongs_to :skill
belongs_to :character_sheet
delegate :name, to: :skill
end
You then use fields_for :character_sheet_skills to create rows on the join table explicitly:
<%= f.fields_for :character_sheet_skills do |cs| %>
<fieldset>
<legend><%= cs.name %></legend>
<div class="field">
<%= cs.label :value %>
<%= cs.number_field :value %>
</div>
<%= cs.hidden_field :skill_id %>
</fieldset>
<% end %>
Instead of a hidden fields you could use a select if you want let the user select the skills.
Of course nothing will show up unless you "seed" the inputs:
class CharacterSheetController < ApplicationController
def new
#character_sheet = CharacterSheet.new do |cs|
# this seeds the association so that the fields appear
Skill.all.each do |skill|
cs.character_sheet_skills.new(skill: skill)
end
end
end
def create
#character_sheet = CharacterSheet.new(character_sheet_params)
if #character_sheet.save
redirect_to #character_sheet
else
render :new
end
end
private
def character_sheet_params
params.require(:character_sheet)
.permit(
:foo, :bar, :baz,
character_sheet_skill_attributes: [:skill_id, :value]
)
end
end
I'm creating an application where a "submission" can be made using a form which creates client details and allows "referrals" to be created depending on the branch(es) that can provide the required service
class Submission < ActiveRecord::Base
has_many :referrals, :inverse_of => :submission, dependent: :delete_all
accepts_nested_attributes_for :referrals, :allow_destroy => true
end
class Referral < ActiveRecord::Base
belongs_to :submission
end
class Branch < ActiveRecord::Base
has_many :referrals
end
Submissions controller:
def new
#submission = Submission.new
#submission.build_client
#submission.client.build_address
#submission.referrals.build
end
def submission_params
params.require(:submission).permit(:consent, :user_id, client_attributes:
[:client_id, :first_name,
address_attributes:
[:first_line, :second_line,]
],
referrals_attributes:
[:branch_id]
)
end
The Submission form:
<%= form_for(#submission) do |f| %>
<%= f.fields_for :referrals do |referral| %>
<%= render 'referral_fields', f: referral %>
<% end %>
<% end %>
_referral_fields.html.erb:
<% Branch.all.where(referrable: true).each do |branch| %>
<label>
<%= check_box_tag 'branch_ids[]', branch.id %>
<%= branch.name %>
</label>
<% end %>
What I want is to have checkboxes for each referrable branch. When a branch is ticked and the submission is created, a referral will be created for that branch. However, when I submit the form, I get a validation error of "Referrals can't be blank". Any idea why this is not working?
Any help is most appreciated
Use collection_check_boxes.
<% # _referral_fields.html.erb %>
<%= f.collection_check_boxes(:branch_ids, Branch.where(referrable: true), :id, :name) do |b|
b.label { b.check_box } # wraps check box in label
end %>
You would need to whitelist submission[referrals_attributes][branch_ids] - not branch_id.
def submission_params
params.require(:submission)
.permit(
:consent,
:user_id,
client_attributes: [
:client_id,
:first_name,
address_attributes: [
:first_line, :second_line,
]
],
referrals_attributes: [:branch_ids]
)
end
Edited.
However for this to work you need to setup a relation between Referral and Branch. In this case you could use either a has_and_belongs_to_many (HABTM) or has_many though: (HMT) relationship.
See Choosing Between has_many :through and has_and_belongs_to_many.
class Referral < ActiveRecord::Base
belongs_to :submission
has_and_belongs_to_many :branches
end
class Branch < ActiveRecord::Base
has_and_belongs_to_many :referrals
end
You need to create a join table as well:
rails g migration CreateBranchReferralJoinTable branch referral
Each "User" has one "Move".
Each "Move" has many "Neighborhood Preferences".
I want to create a form on the "/user/(:id)/edit" page that lets a person edit their "move", and "neighborhood_preferences".
Currently, the form displays correctly. But when I submit the form, I get this error Move(#2168853040) expected, got ActionController::Parameters(#2158484920).
How can I save both a new move, and the neighborhood_preferences?
View for Users#edit
<%= form_for(#user) do |f| %>
<%= hidden_field_tag "user[move][neighborhood_ids][]", nil %>
<% #neighborhoods.each do |n| %>
<%= check_box_tag "user[move][neighborhood_ids][]",
n.id, # the value to submit
#user.move.neighborhood_ids.include?(n.id), # Check the box on load
id: dom_id(n) # add a unique category based on the object
%>
<%= label_tag dom_id(n), n.name %>
<br/>
<% end %>
<%= f.submit "Save Changes" %>
<% end %>
Controller for Users#edit
def edit
#user = User.find(params[:id])
#neighborhoods = Neighborhood.all
end
private
def user_params
params.require(:user).permit(
:email,
:age,
:gender,
:university,
:grad_year,
:occupation,
:company,
# Allow form to submit neighborhood_ids for a user's move.
move: [neighborhood_ids: []]
)
end
Models
class User < ActiveRecord::Base
# attr_accessible :provider, :uid, :name, :email
validates_presence_of :name
has_one :move
accepts_nested_attributes_for :move, allow_destroy: true
class Move < ActiveRecord::Base
belongs_to :user
has_many :neighborhood_preferences
has_many :neighborhoods, through: :neighborhood_preferences
accepts_nested_attributes_for :neighborhood_preferences, allow_destroy: true
end
class NeighbhoodPreference < ActiveRecord::Base
belongs_to :neighborhood
belongs_to :move
end
A users can have many favorites top_songs,top_movies through songs and movies table.
A user registered user(current_user) want to post his favorites movies and songs.
Perhaps all Model association are right, i am stuck in controller and view (form).
When i submit from, i gets errors-
Can't mass-assign protected attributes: songs
How can i achieve this please?
all codes are below.
User Model
class User < ActiveRecord::Base
attr_accessible :id, :name_special_char, :screenname, :fullname, :username, :prefix, :firstname, :lastname,:middlename, :suffix, :age, :sex, :email,
:top_movies_attributes,:top_songs_attributes
has_many :top_movies
has_many :movies, through: :top_movies
has_many :top_songs
has_many :songs, through: :top_songs
accepts_nested_attributes_for :top_songs, :allow_destroy => true
accepts_nested_attributes_for :top_movies, :allow_destroy => true
end
Movie Model
class Movie < ActiveRecord::Base
attr_accessible :name
has_many :top_movies
has_many :users, through: :top_movies
end
TopMovie Model
class TopMovie < ActiveRecord::Base
belongs_to :user
belongs_to :movie
# attr_accessible :title, :body
end
Song Model
class Song < ActiveRecord::Base
attr_accessible :name
has_many :top_songs
has_many :users, through: :top_songs
end
TopSong Model
class TopSong < ActiveRecord::Base
belongs_to :user
belongs_to :song
# attr_accessible :title, :body
end
Controller
class MyTopFivesController < ApplicationController
def new
#favorites = current_user
#favorites=#favorites.movies.build()
#favorites=#favorites.songs.build()
respond_to do |format|
format.html # new.html.erb
format.json { render json: #useraccounts_my_top_fife }
end
end
def create
#favorites = current_user(params[:user])
#favorites.save!
# Here i have stuck. i am not sure how to save.
end
view form
<%=nested_form_for #favorites ,:url=>favorites_path(#favorites),:method=>'post' do |f| %>
<label >Songs</label>
<%= f.fields_for :songs do |songs| %>
<div id="Topsongs" >
<div class="input-control text span5 place-left ">
<%= songs.text_field :name,:placeholder=>"songs name.." %>
</div>
<div class="span1 place-left">
<%= songs.link_to_remove "", :class=>"icon-minus" %>
</div>
</div>
<% end %>
<span >
<%= f.link_to_add "", :songs, :class=>"icon-plus", :data => { :target => "#Topsongs" } %>
</span>
<label >movies</label>
<%= f.fields_for :movies do |movies| %>
<div id="Topmovies">
<div class="input-control text span5 place-left ">
<%= movies.text_field :name,:placeholder=>"movies name.." %>
</div>
<div class="span1 place-left">
<%= movies.link_to_remove "", :class=>"icon-minus" %>
</div>
</div>
<% end %>
<span>
<%= f.link_to_add "", :movies, :class=>"icon-plus",:style=>"font-size: 14px;", :data => { :target => "#Topmovies" } %>
</span>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
There are two options for setting up the associations here. One you have used by creating two join models for top songs and top movies. And other, to use polymorphic association.
Lets use polymorphic association. We are going to use User, Movie, Song and Favourite models for this stuff. The Favourite model will contain the polymorphic fields.
User.rb
class User < ActiveRecord::Base
attr_accessible :id, :name_special_char, :screenname, :fullname, :username, :prefix, :firstname, :lastname,:middlename, :suffix, :age, :sex, :email
has_many :favourites
has_many :movies, through: :favourites, source: :favouritable, source_type: 'Movie'
has_many :songs, through: :favourites, source: :favouritable, source_type: 'Song'
end
Movie.rb
class Movie < ActiveRecord::Base
attr_accessible :name
has_many :favourites, as: :favouritable
has_many :users, through: :favourites
end
Song.rb
class Song < ActiveRecord::Base
attr_accessible :name
has_many :favourites, as: :favouritable
has_many :users, through: :favourites
end
Favourite.rb
class Favourite < ActiveRecord::Base
belongs_to :users
belongs_to :favouritable, polymorphic: true
end
We also need to create the migration for new model "Favourite". As of now, we just need 3 columns ie. user_id, favouritable_id, favouritable_type. Here favouritable_type and favouritable_id are the polymorphic fields. favouritable_type is a string and favouritable_id is reference type.
Migration File
class CreateFavourites < ActiveRecord::Migration
def change
create_table :favourites do |t|
t.integer :user_id
t.references :favouritable, polymorphic: true
t.timestamps
end
end
end
Now, as we are going to mark some movies and songs to be favourite for a user, then we can place the code for building the data in UsersController instead of creating another controller or we can also create a controller for Favourites. I am going to use UsersController here. I am using update action to update the favourites as we don't need any extra functionality here. You can add a new action if you want.
In UsersController.rb
def edit_favourites #or some generic name
#user = current_user.includes(:movies, :songs)
#movies = Movie.all
#songs = Song.all
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
redirect_to users_path #user index page
else
if params[:user][:movie_ids].present? or params[:user][:song_ids].present?
render :edit_favourites
else
render :edit
end
end
end
edit_favourites.html.erb
<%= form_for(#user) do |f| %>
<div class="fields">
<%= f.label :movie_ids, "Favourite Movies: " %>
<%= f.collection_select :movie_ids, #movies, :id, :name, {}, multiple: true %>
</div>
<div class="fields">
<%= f.label :song_ids, "Favourite Songs: " %>
<%= f.collection_select :song_ids, #songs, :id, :name, {}, multiple: true %>
</div>
<% end %>
Also, Add the new action to routes.
I'm developing an app for college where a user can log on & upload details of a hiking trail.
So far everything is working & I have also implemented a nested form for photos in each hiking trail. A user can log-on & create a hike.
I would like to display all the hikes which the user created in there show/profile page but when I've set up the relationships in my database & the has_many & belongs_to options in my model. I've also tried to do this with nested accepts_nested_attributes_for :hikingtrails it does none of this works.
I've checked my database when a hikingtrail is created by a user it is not updating the user_id field in the table.
I'm not sure if I'm approaching this entirely the wrong way, should I be looking at polymorphic associations?
class User < ActiveRecord::Base
attr_accessible :user_name, :email, :password, :password_confirmation, :photos_attributes, :hikingtrails_attributes
has_many :hikingtrails
accepts_nested_attributes_for :hikingtrails, :allow_destroy => :true, :reject_if => :all_blank
class Hikingtrail < ActiveRecord::Base
attr_accessible :description, :name, :looped, :photos_attributes,:directions_attributes, :user_id
has_many :photos
has_many :trails
has_many :directions
belongs_to :user
users/show.html.erb
<div class="page-header">
<h1>Your Profile</h1>
</div>
<p>
<b>username:</b>
<%= #user.user_name %>
</p>
<p>
<b>email:</b>
<%= #user.email %>
</p>
<h4>Small Photos</h4>
<% #user.photos.each do |photo| %>
<%= image_tag photo.image_url(:thumb).to_s %>
<% end %>
<h4>Hiking Trails</h4>
<% #user.hikingtrails.each do |hk| %>
<%= hk.name %>
<% end %>
<%= link_to "Edit your Profile", edit_user_path(current_user), :class => 'btn btn-mini' %>
You didn't add :user_id to your accessible attributes in the Hikingtrail model. Try the following:
attr_accessible :description,
:duration_hours,
:duration_mins,
:name,
:looped,
:addr_1,
:addr_2,
:addr_3,
:country,
:latitude,
:longitude,
:photos_attributes,
:trails_attributes,
:directions_attributes,
:user_id
UPDATE:
After seeing the form code, I think it's probably not necessary to do the above and could potentially also be unsafe. Instead, don't set the user_id through mass assignment, but handle user assignment in your controller like so:
class HikingtrailsController < ApplicationController
# ...
def create
#hikingtrail = Hikingtrail.new(params[:hikingtrail])
#hikingtrail.user = current_user
if #hikingtrail.save
# ...
else
# ...
end
end
end
Hope this helps :)