I have 3 models :
user.rb
class User < ApplicationRecord
has_one :profile, inverse_of: :user, dependent: :destroy
accepts_nested_attributes_for :profile
has_many :bookings, inverse_of: :user, dependent: :destroy
has_many :owner_bookings, foreign_key: 'owner_id', class_name: 'Booking'
end
profile.rb
class Profile < ApplicationRecord
# mount_uploader :avatar, AvatarUploader
belongs_to :user, inverse_of: :profile
accepts_nested_attributes_for :user
end
booking.rb
class Booking < ApplicationRecord
belongs_to :user
belongs_to :owner, class_name: :User
belongs_to :poi
end
After a create booking, I would like to update the user profile (if some changes)
my form :
<%= simple_form_for [#poi.poitable, #booking] do |f| %>
<%= f.simple_fields_for #user.profile do |profile| %>
<%= profile.input :first_name,
input_html: { value: #user.profile.first_name } %>
<%= profile.input :last_name, input_html: { value: #user.profile.last_name } %>
<% end %>
<%= f.input :owner_id, input_html: { value: #poi.user.id } %>
<%= f.input :poi_id, input_html: { value: #poi.id } %>
<%= f.input :user_id, input_html: { value: #user.id } %>
<%= f.submit %>
<% end %>
booking_controller :
def new
#user = current_user
#poi = Sleep.friendly.find(params[:sleep_id]).poi
#booking = Booking.new
end
def create
#user = current_user
#poi = Sleep.friendly.find(params[:sleep_id]).poi
#booking = Booking.new(booking_params)
if #booking.save
#booking.user.profile.update_attribute(booking_params[:user_profile_attributes])
end
private
def booking_params
params.require(:booking).permit(
:poi_id,
:owner_id,
:user_id,
user_profile_attributes: [:user_id, :first_name, :first_name],
)
end
booking_params return only :poi_id, :owner_id, user_id, how can I get user_profile params to update #user.profile ?
Related
I have a page that displays a title and then a group of links. It looks like this:
Right now they are displaying all the links that pertain to the entire page and not to the individual titles. I would like for each title to only the links that pertain to it. I am using rails 4, cocoon and haml. Any ideas as to how I might do that?
essential.rb
class Essential < ActiveRecord::Base
has_many :favorites, :dependent => :destroy
has_many :catalogs, :dependent => :destroy
has_many :labels, :dependent => :destroy
has_many :members,:dependent => :destroy
has_many :sub_catalogs, through: :catalogs, :dependent => :destroy
has_many :sub_favorites, through: :favorites, :dependent => :destroy
has_many :instruments, through: :members, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :favorites, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :catalogs, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :labels, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :members, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :sub_catalogs, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :sub_favorites, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :instruments, :reject_if => :all_blank, :allow_destroy => true
validates :band_name, :bio, :image, presence: true
has_attached_file :image, styles: { medium: "400x400#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
catalog.rd
class Catalog < ActiveRecord::Base
belongs_to :essential
has_many :sub_catalogs, :dependent => :destroy
accepts_nested_attributes_for :sub_catalogs, :reject_if => :all_blank, :allow_destroy => true
end
sub_catalog.rb
class SubCatalog < ActiveRecord::Base
belongs_to :catalog
end
essentials_controller.rb
class EssentialsController < ApplicationController
before_action :find_essential, only: [:show, :edit, :update, :destroy]
def index
#essential = Essential.all.order("created_at DESC")
end
def new
#essential = current_user.essentials.build
end
def show
end
def create
#essential = current_user.essentials.build(essential_params)
if #essential.save
redirect_to #essential, notice: "Successfully created new essential"
else
render 'new'
end
end
def edit
end
def update
if #essential.update(essential_params)
redirect_to #essential
else
render 'edit'
end
end
def destroy
#essential.destroy
redirect_to root_path, notice: "Successfully deleted Essential"
end
private
def essential_params
params.require(:essential).permit(:band_name, :bio, :image, :country, :album,
favorites_attributes: [:id, :song_title, :url, :url_type, :_destroy, sub_favorites_attributes: [:id, :fav_url, :fav_url_type, :_destroy]],
members_attributes: [:id, :band_member, :position, :_destroy, instruments_attributes: [:id, :position, :_destroy]],
labels_attributes: [:id, :record_label, :_destroy],
catalogs_attributes: [:id, :song_name, :_destroy, sub_catalogs_attributes: [:id, :sub_url, :sub_url_type, :_destroy] ])
end
def find_essential
#essential = Essential.find(params[:id])
end
end
show.html.haml
.main_content
#essential_top.row
.col-md-4
= image_tag #essential.image.url(:medium), class: "essential_image"
.col-md-8
#essential_info
%h1= #essential.band_name
%p.bio= #essential.bio
.row
.col-md-6
#favorites
%h2 Favorites
%table
- #essential.favorites.each do |favorite|
%tr
%td= favorite.song_title
- #essential.sub_favorites.each do |sub_favorite|
%td= link_to sub_favorite.fav_url_type, "https://www.#{sub_favorite.fav_url}"
.col-md-6
#catalogs
%h2 Catalogs
%table
- #essential.catalogs.each do |catalog|
%tr
%td= "#{catalog.song_name} |"
- #essential.sub_catalogs.each do |sub_catalog|
%td= link_to sub_catalog.sub_url_type, "https://www.#{sub_catalog.sub_url}"
.row
.col-md-6
#labels
%h2 Record Label(s)
%table
- #essential.labels.each do |label|
%tr
%td= label.record_label
.col-md-6
#members
%h2 Members
%table
- #essential.members.each do |member|
%tr
%td= member.band_member
- #essential.instruments.each do |instrument|
%td= instrument.position
.col-md-12
= link_to "Back", root_path, class: "btn btn-secondary"
- if user_signed_in?
= link_to "Edit", edit_essential_path, class: "btn btn-secondary"
= link_to "Delete", essential_path, method: :delete, data: {confirm: "Are you sure?" }, class: "btn btn-secondary"
form.html.haml
= simple_form_for #essential, html: { multipart: true } do |f|
- if #essential.errors.any?
#errors
%p
= #essential.errors.count
Prevented this essential from saving
%ul
- #essential.errors.full_message.each do |msg|
%li = msg
.panel-body
= f.input :band_name, placeholder: "Band Name", label: false, input_html: { class: 'form-control form-inline'}
= f.input :bio, placeholder: "Bio", label: false, input_html: { class: 'form-control'}
= f.input :image, placeholder: "Image", label: false, input_html: { class: 'form-control'}
= f.input :country, collection: ["England", "United States", "Ireland", "Germany", "France", "Finalnd", "Sweden", "Wales", "Scotland", "Denmark", "Iceland", "Spain", "Italy"], input_html: { class: "form-control form-input" }
= f.input :album, collection: 1..25, input_html: { class: "form-control" }
.row
.col-md-6
%h3 Favorites
#favorites
= f.simple_fields_for :favorites do |favorite|
= render 'favorite_fields', f: favorite
.links
= link_to_add_association 'Add Favorite', f, :favorites, class: 'btn btn-secondary add-button'
.col-md-6
%h3 Catalog
#catalogs
= f.simple_fields_for :catalogs do |catalog|
= render 'catalog_fields', f: catalog
.links
= link_to_add_association 'Add Catalog', f, :catalogs, class: 'btn btn-secondary add-button'
.row
.col-md-6
%h3 Record Label(s)
#labels
= f.simple_fields_for :labels do |label|
= render 'label_fields', f: label
.links
= link_to_add_association 'Add Record Label', f, :labels, class: 'btn btn-secondary add-button'
.col-md-6
%h3 Band Members
#members
= f.simple_fields_for :members do |member|
= render 'member_fields', f: member
.links
= link_to_add_association 'Add Band Member', f, :members, class: 'btn btn-secondary add-button'
= f.button :submit, class: 'btn btn-primary'
In your view file, look at the catalogs section and change it to
%h2 Catalogs
%table
- #essential.catalogs.each do |catalog|
%tr
%td= "#{catalog.song_name} |"
- catalog.sub_catalogs.each do |sub_catalog|
%td= link_to sub_catalog.sub_url_type, "https://www.#{sub_catalog.sub_url}"
change #essential to the local variable catalog.
i have job model, skill model and job_skill model
class Job < ActiveRecord::Base
has_many :job_skills
has_many :skills ,through: :job_skills
accepts_nested_attributes_for :job_skills
class Skill < ActiveRecord::Base
has_many :job_skills
has_many :jobs ,through: :job_skills
accepts_nested_attributes_for :job_skills
class JobSkill < ActiveRecord::Base
belongs_to :skill
belongs_to :job
accepts_nested_attributes_for :job
accepts_nested_attributes_for :skill
And jobs controller
class JobsController < ApplicationController
def new
#job = Job.new
#job.job_skills.build
end
def create
#job = Job.new(job_params)
#job.save
end
private
def job_params
params.require(:job).permit(:occupation, :industry, :location,job_skills_attributes:[])
end
and job form is
= form_for #job do |f|
= f.label :location
= f.text_field :location
.clear
= f.label "industry*"
= f.text_field :industry
.clear
= f.label :occupation
= f.text_field :occupation
.clear
= f.label "Skill Required*"
= f.fields_for(:job_skills) do |s|
= s.select :skill_id, Skill.all.collect{|p| [p.skill, p.id]},{}, {:multiple => true, :class=> "chosen-select multiple-select-skills"}
= f.submit "submit"
only job get save. jobs_skills doesnt save. in job params i get only jobs data. what could be the reason. please help.!!
Update your form_for to nested_form_for
= nested_form_for #job do |f|
= f.label :location
= f.text_field :location
.clear
= f.label "industry*"
= f.text_field :industry
.clear
= f.label :occupation
= f.text_field :occupation
.clear
= f.label "Skill Required*"
= f.fields_for(:job_skills) do |s|
= s.select :skill_id, Skill.all.collect{|p| [p.skill, p.id]},{}, {:multiple => true, :class=> "chosen-select multiple-select-skills"}
In this case accepts_nested_attributes_for is not required.
Your models should be
class Job < ActiveRecord::Base
has_many :job_skills
has_many :skills ,through: :job_skills
class Skill < ActiveRecord::Base
has_many :job_skills
has_many :jobs ,through: :job_skills
class JobSkill < ActiveRecord::Base
belongs_to :skill
belongs_to :job
And jobs controller
class JobsController < ApplicationController
def new
#job = Job.new
##job.job_skills.build #=> No need of buid
end
def create
#job = Job.new(job_params)
#job.save
end
private
# Add skill_ids to job_params
def job_params
params.require(:job).permit(:occupation, :industry, :location, skill_ids:[])
end
and job form
= form_for #job do |f|
= f.label :location
= f.text_field :location
.clear
= f.label "industry*"
= f.text_field :industry
.clear
= f.label :occupation
= f.text_field :occupation
.clear
= f.label "Skill Required*"
= s.select :skill_ids, Skill.all.collect{|p| [p.skill, p.id]},{}, {:multiple => true, :class=> "chosen-select multiple-select-skills"}
= f.submit "submit"
Hope this will be helpful
i have model poll with nested attributes poll_items:
class Poll < ActiveRecord::Base
ITEMS_COUNT_MAX = 5
attr_accessible :from_date, :question, :results_hidden, :to_date, :owner_id, :poll_items_attributes
belongs_to :owner, polymorphic: true
has_many :poll_items, dependent: :destroy
has_many :poll_votes, through: :poll_items
accepts_nested_attributes_for :poll_items, allow_destroy: true,
reject_if: proc { |attributes| attributes['answer'].blank? }
#validates :owner, :question, :from_date, :to_date, presence: true
#validate :validate_duplicate, on: :create
validate :validate_max_poll_items, on: :update
after_initialize :defaults
...................................................................
model pollItem
attr_accessible :answer
attr_readonly :poll_votes_count
belongs_to :poll
has_many :poll_votes, dependent: :destroy
has_many :users, through: :poll_votes
validates :poll, :answer, presence: true
validate :validate_duplicate, on: :create
scope :editable, lambda { |u|
unless u.moderator?
where(:poll.owner.user_id => u.id).where(:created_at.gt Settings.edit_delay.minutes.ago)
end
}
private
def validate_duplicate
errors.add(:base, :duplicate) unless poll.poll_items.where(answer: answer).empty?
end
end
Poll_controller:
class PollsController < ApplicationController
before_filter :authenticate_user!
before_filter :set_poll, only: [:show, :edit, :update, :destroy]
before_filter :find_owner, only: [:new, :create]
def new
#poll = Poll.new
end
def create
#poll = Poll.new params[poll_params]
##poll.owner = #owner
respond_to do |format|
if #poll.save
format.html { redirect_to [:edit, #poll], notice: 'Опрос был успешно создан.' }
else
format.html { render :new }
end
end
end
def show
end
def edit
#poll.poll_items.build
end
def update
if #poll.editable?(current_user)
if #poll.update_attributes params[:poll]
respond_to do |format|
format.html { redirect_to [:edit, #poll], notice: 'Опрос был успешно обновлен.' }
end
else
respond_to do |format|
format.html { render :edit, alert: #poll.errors }
end
end
end
end
def destroy
#poll.destroy
respond_to do |format|
format.html { redirect_to #owner, notice: 'Опрос был успешно удален.' }
end
end
private
def poll_params
params.require(:poll).permit(:from_date, :question, :results_hidden, :to_date,
:owner_id, poll_items_attributes: [:id, :unswer, :_destroy])
end
protected
def set_poll
#poll = Poll.find(params[:id])
#owner = #poll.owner
end
def find_owner
#owner = case
when params[:post_id]
Post.visible(current_user).find(params[:post_id])
when params[:blog_post_id]
BlogPost.with_privacy(current_user).find(params[:blog_post_id])
end
end
end
I installed gem cocoon:
next i create view new.html.haml:
%h1= title "Новый опрос"
= simple_form_for #poll do |f|
= f.error_messages header_message: nil
= f.input :question, disabled: !#poll.editable?(current_user), input_html: { class: 'input-block-level' }
= f.input :results_hidden, as: :boolean, inline_label: 'Скрыть результаты до окончания опроса', label: false
= f.input :from_date, as: :datetime, input_html: { class: 'poll_date' }
= f.input :to_date, as: :datetime, input_html: { class: 'poll_date' }
.items-index
%h3#poll-items Варианты ответа (не больше пяти)
= f.simple_fields_for :poll_items do |poll|
= render 'poll_items_fields', f: poll
= link_to_add_association 'Добавить еще вариант', f, :poll_items
.form-actions
= f.button :submit, 'Опубликовать опрос', class: 'btn-bg'
%p
Вернуться к посту:
= link_to #owner
poll_items_fields.html.haml:
.poll_row
.poll_item
= f.input :answer, input_html: { class: 'ctrlenter expanding' }, label: false, placeholder: 'Введите вариант ответа'
= link_to_remove_association "удалить", f
I open page new for creating new poll, but only field for new name quation poll and button "create poll". No fields for adding poll_items. I thinkm dont render form poll_items_fields.html.haml. But why? How fix?
If I understood correctly, your new method should look like this
def new
#poll = Poll.new
#poll.poll_items.build
end
And also you have unswer instead of answer in poll_items_attributes, so fix that too.
def poll_params
params.require(:poll).permit(:from_date, :question, :results_hidden, :to_date, :owner_id, poll_items_attributes: [:id, :answer, :_destroy])
end
Update:
You should also remove attr_accessible :from_date, :question, :results_hidden, :to_date, :owner_id, :poll_items_attributes from your Poll model as Rails 4 uses strong parameters.
And also this line #poll = Poll.new params[poll_params] in create method should look like this #poll = Poll.new(poll_params)
There are the following models:
class Discount < ActiveRecord::Base
belongs_to :content, polymorphic: true
validates :value, presence: true
end
class TimeDiscount < ActiveRecord::Base
has_one :discount, as: :content, dependent: :destroy
validates :start_time, :end_time, presence: true
accepts_nested_attributes_for :discount
end
And the following controller:
class Admin::TimeDiscountsController < ApplicationController
def new
#time_discount = TimeDiscount.new
end
def create
#time_discount = TimeDiscount.new(time_discount_params)
if #time_discount.save
redirect_to root_path
else
render 'new'
end
end
private
def time_discount_params
params.require(:time_discount).permit.tap do |whitelisted|
whitelisted[:start_time] = params[:time_discount][:start_time]
whitelisted[:end_time] = params[:time_discount][:end_time]
whitelisted[:discount_attributes] = params[:time_discount][:content]
end
end
end
Form:
= form_for #time_discount, url: admin_time_discounts_path do |f|
.row
= f.label :start_time
= f.text_field :start_time
.row
= f.label :end_time
= f.text_field :end_time
= f.fields_for :content do |discount|
.row
= discount.label :value
= discount.text_field :value
.row
= f.submit "Добавить"
But 'create' action generates 'ActiveModel::ForbiddenAttributesError' in TimeDiscount.new line. I use Rails 4. How can I fix it? Thanks.
def time_discount_params
params.require(:time_discount).permit(:start_time, :end_time, content: [:id, :start_time, :end_time])
end
This is probably what you want instead of that method you have defined in the above. This is assuming you are creating it via something like this:
= form_for #time_discount, url: admin_time_discounts_path do |f|
.row
= f.label :start_time
= f.text_field :start_time
.row
= f.label :end_time
= f.text_field :end_time
= f.fields_for :content, #time_discount.content.build do |discount|
.row
= discount.label :value
= discount.text_field :value
.row
= f.submit "Добавить"
give that a go.
I have three controllers - users, stories, categories. I want when I am logged in as a administrator to create categories and then to write stories for every category. I did part of the task but in DB in table Stories category_id is empty and I cannot understand how to fix it. Here is part of my code:
stories/new.html.erb:
<%= form_for(#story) do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= f.collection_select :category_id, #categories, :id, :title %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Add" %>
</div>
<% end %>
stories_controller.rb:
class StoriesController < ApplicationController
before_filter :admin_user
def new
#story = Story.new
#categories = Category.all
#title = "Add news"
end
def create
#categories = Category.all
#story = current_user.stories.build(params[:story])
if #story.save
flash[:success] = "Successfullly added news"
redirect_to #story
else
#title = "Add news"
render 'new'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
story.rb:
class Story < ActiveRecord::Base
attr_accessible :title, :content
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :content, :presence => true
validates :user_id, :presence => true
default_scope :order => 'stories.created_at DESC'
end
category.rb:
class Category < ActiveRecord::Base
attr_accessible :title
has_many :stories
validates :title, :presence => true,
:length => { :within => 6..40 }
end
user.rb:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
has_many :stories
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => true
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
You need add attr_accessible :category_id to your story model
Its preventing mass assignment in your controllers create method. Alternatively you could pull out the category_id from your params hash and assign it on a separate line.