Edit and Update for assosiated model Rails - ruby-on-rails

I tried to create edit and update action for my assosiated model named as Entity.
But When edit pages pop up no saved data shown. Means it is showing all field as empty and when I put values in it, creates a another object.
And also validation messages are not showing
Entities Controller
class EntitiesController < ApplicationController
def edit
#schema = Schema.find(params[:schema_id])
#entity = #schema.entities.find(params[:id])
end
def update
#schema = Schema.find(params[:schema_id])
#entity = #schema.entities.find(params[:id])
if #entity.update(entity_params)
redirect_to schema_entities_path(#schema)
else
render 'edit'
end
end
private
def entity_params
params.require(:entity).permit(:clientId, :name, :description, :mnemonic)
end
end
edit form for it:
<%= form_for([#schema, #schema.entities.build], data: { turbo: false }) do |f| %>
<%= f.text_field :clientId, placeholder:"ClientId" %>
<%= f.text_area :name, placeholder: "Name" %>
<%= f.text_area :description, placeholder: "Description" %>
<%= f.text_area :mnemonic, placeholder: "Mnemonic" %>
<%= f.submit 'Submit' %>
<% if #entity.errors.any? %>
<div id="error_explanation">
<% #entity.errors.full_messages.each do |msg| %>
<p class="error_msg"><%= msg %></p>
<% end %>
</div>
<% end %>
<% end %>
Its model:
class Entity < ApplicationRecord
belongs_to :schema
has_many :fields, dependent: :destroy
has_many :joins, through: :fields
validates :name, presence: true, uniqueness: true
def self.search(search)
where("name LIKE ?", "%#{search}%")
end
end
This is how I am passing values from index page:
<%= link_to 'Edit', edit_schema_entity_path(schema_id: #schema.id, id: data.id) if data.id %>

Related

Why is my party not being created and saved to the database?

I have my parameters whitelisted and when I look at the output of party_params I see that they are permitted but when I got to save the instance into the database it gives me a rollback transaction in the console. I've tried just create, create then save, new then save. Is there something I am missing?
#controller
class PartiesController < ApplicationController
def new
#party = Party.new
end
def create
#party = Party.create(party_params)
redirect_to party_path(#party)
end
private
def party_params
params.require(:party).permit(
:name,
:trainer_id,
:pokemon1_id
)
end
end
#model
class Party < ApplicationRecord
belongs_to :trainer
belongs_to :pokemon
validates :name, presence: true
end
#view
<h1>Create a New Pokemon Party</h1>
<p>Select 6 Pokemon</p>
<%= form_for(#party) do |f| %>
<label>Party Name:</label>
<%= f.text_field :name %><br>
<label>Trainer Name:</label>
<%= collection_select(:party, :trainer_id, Trainer.order(:id), :id, :name, include_blank: true) %><br>
<label>Pokemon:</label>
<%= collection_select(:party, :pokemon1_id, Pokemon.order(:id), :id, :nickname, include_blank: false) %><br>
<%= f.submit %>
<% end %>
#schema
create_table "parties", force: :cascade do |t|
t.string "name"
t.integer "pokemon1_id"
t.integer "trainer_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
Lets start with the models. If you want a party to be able to include multiple pokemon you need to place the foreign key in the other model:
class Party < ApplicationRecord
belongs_to :trainer
has_many :pokemons # references the pokemons.party_id column
end
class Pokemon < ApplicationRecord
belongs_to :party # pokemons needs a `party_id` column
end
class AddPartyToPokemons < ActiveRecord::Migration
def change
add_reference :pokemons, :party, null: false, foreign_key: true
remove_column :parties, :pokemon1_id
end
end
This is very simplefied and assumes that Pokemon is an individual Pokemon and not the entire species and can only belong to a single party. Otherwise you need a many-to-many assocation with a join table/model.
In your controller you need to check if creating the record was actually successful and respond accordingly:
class PartiesController < ApplicationController
def new
#party = Party.new
end
def create
#party = Party.new(party_params)
if #party.save
redirect_to #party
else
render :new
end
end
private
def party_params
params.require(:party).permit(
:name,
:trainer_id,
pokemon_ids: []
)
end
end
If the user input is invalid this will render the app/parties/new.html.erb view and respond with it.
While you could use pry or byebug to step into the controller and check the errors you want to display the validation errors to the user in the view anyways so that they know what to actually do to correct the form:
<h1>Create a New Pokemon Party</h1>
<p>Select 6 Pokemon</p>
<%= form_for(#party) do |f| %>
<% if #party.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#party.errors.count, "error") %> prohibited this party from being saved:</h2>
<ul>
<% #article.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<%
# group labels and inputs in an element instead of abusing BR tags
# this lets you style the content with CSS
-%>
<div class="field">
<%# use f.label as it sets the `for=` attribute which is important for screen readers -%>
<%= f.label :name, 'Party Name:' %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :trainer_id, 'Trainer Name:' %>
<%# call the helper on the form builder to bind the input to the model -%>
<%= f.collection_select(:trainer_id, Trainer.order(:id), :id, :name, include_blank: true) %>
</div>
<div class="field">
<%= f.label :pokemon_ids, 'Pokemon:' %>
<%# call the helper on the form builder to bind the input to the model -%>
<%= f.collection_select(:pokemon_ids, Pokemon.order(:id), :id, :nickname, include_blank: false, multiple: true) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Note f.collection_select(:pokemon_ids, ...). This is a special setter/getter is generated by has_many :pokemons.

Rails fields_for not rendering on page

I am trying to implement a form that has associated videos when I create a new tutorial. The issue is that my form is not rendering whenever I visit the page. Could anyone help, please?
This is myapp/views/admin/tutorials/new.html.erb
<h2>New Tutorial</h2>
<%= form_for [:admin, #tutorial] do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "block col-4 field" %>
<%= f.label :description %>
<%= f.text_area :description, class: "block col-4 field" %>
<%= f.label :thumbnail %>
<%= f.text_field :thumbnail, class: "block col-4 field" %>
<h3>Videos</h3>
<%= f.fields_for :videos do |builder| %>
<%= builder.label :youtube_url %>
<%= builder.text_field :youtube_url, class: "block col-4 field" %>
<%= builder.label :video_id %>
<%= builder.text_field :video_id, class: "block col-4 field" %>
<% end %>
<%= f.submit "Save", class: "mt2 btn btn-primary mb1 bg-teal" %>
<% end %>
This is my Video model
class Video < ApplicationRecord
has_many :user_videos
has_many :users, through: :user_videos
belongs_to :tutorial
validates_presence_of :position
end
And my Tutorial model
class Tutorial < ApplicationRecord
has_many :videos, -> { order(position: :ASC) }, dependent: :destroy
acts_as_taggable_on :tags, :tag_list
accepts_nested_attributes_for :videos
scope :without_classroom, -> { where(classroom: false) }
end
My controller:
class Admin::TutorialsController < Admin::BaseController
def new
#tutorial = Tutorial.new
end
def create
#tutorial = Tutorial.new(tutorial_params)
if #tutorial.save
flash[:success] = "Successfully created tutorial!"
redirect_to tutorial_path(#tutorial)
else
render :new
end
end
def edit
#tutorial = Tutorial.find(params[:id])
end
def update
tutorial = Tutorial.find(params[:id])
if tutorial.update(tutorial_params)
flash[:success] = "#{tutorial.title} tagged!"
end
redirect_to edit_admin_tutorial_path(tutorial)
end
private
def tutorial_params
params.require(:tutorial).permit(:tag_list, :title, :description, :thumbnail)
end
end
The reason nothing's rendered is that the videos association is empty. For example if you add #tutorial.videos.build in the new controller action, then you will get one set of the fields, and if you have multiple videos in the association (whether persisted or not) you would get one set of the fields per video.

how to add details in two database table in one submit

I have 3 tables: coaches, categories and also a join table categories_coaches, on submit I want to store category_id and coach_id in join table categories_coaches and name, email, university, batch, phone in coach table. how to do so?
now details are storing in coach table but not storing in join table
please help me to solve this problem.
coach.rb
class Coach < ActiveRecord::Base
has_and_belongs_to_many :categories
end
category.rb
class Category < ActiveRecord::Base
belongs_to :coach
end
registrationcontroller.erb
class Coaches::RegistrationsController < Devise::RegistrationsController
def new
#individual=#individual ||= Coach.new
super
end
def create
build_resource sign_up_params
#individual=#individual ||= Coach.new
super
end
private
def sign_up_params
params.require(:coach).permit(:name, :email, :university, :batch, :linkedin_url, :code, :phone,category_ids: []
)
end
end
view page
<%= simple_form_for(#individual, as: :coach, url: registration_path(:coach)) do |f| %>
<%= f.input :name, required: true, %>
<%= f.input :university %>
<%= f.input :batch %>
<%= f.input :email%>
<%= f.input :phone%>
<div class="category-scroll">
<% Category.all.each do |c| %>
<% if c.parent_id != nil %>
<div class="category-left">
<%= check_box_tag "category_ids[]", c.id, false, :id => "category_ids_#{c.id}" %>
<%= c.name %>
</div>
<% else %>
<b><%= c.name %></b>
<% end %>
<% end %>
</div>
<div class="form-group">
<%= f.button :submit, "SUBMIT", class: "apply-continue_form" %
<% end %>
What you've mentioned sounds like a has_and_belongs_to_many relationship to me.
I'll detail what you should do, and the underlying mechanics of the association:
#app/models/coach.rb
class Coach < ActiveRecord::Base
has_and_belongs_to_many :categories
end
#app/models/category.rb
class Category < ActiveRecord::Base
has_and_belongs_to_many :coaches
end
This, as opposed to the has_many :through relationship, does most of the legwork for you. You were correct in setting up your join_table as you did:
The importance of getting this right is that each time you CRUD either your Coach or Category objects, you'll have access to their associated data through the :categories and :coaches methods respectively.
Thus, you'll be able to populate the data like this:
#config/routes.rb
resources :coaches #-> url.com/coaches/new
#app/controllers/coaches_controller.rb
class CoachesController < ApplicationController
def index
#coaches = Coach.all
end
def new
#coach = Coach.new
end
def create
#coach = Coach.new coach_params
end
private
def coach_params
params.require(:coach).permit(:name, :email, :university, :batch, :phone, :categories)
end
end
This will then allow you to make the following view:
#app/views/coaches/new.html.erb
<%= form_for #coach do |f| %>
<%= f.text_field :name %>
<%= f.email_field :email %>
<%= f.text_field :university %>
<%= f.text_field :batch %>
<%= f.text_field :phone %>
<%= f.collection_select :categories, Category.all, :id, :name %>
<%= f.submit %>
<% end %>

Rails 4.2: Client Side Validations for Associations

I have a complex form with associations that I would like to view validation errors inline in real-time. I stumbled upon RailsCasts episode Client Side Validations and decided to take that approach and installed the gem.
gem 'client_side_validations',
github: "DavyJonesLocker/client_side_validations",
branch: "4-2-stable"
As required by the gem, I placed validate: true at the top of the form helper and saw that it only worked on attribute fields and not on the associated objects.
For example, when the field name is blank, it displays the error inline stating can't be blank. When the user has not selected a program, I would like it to inform the user Need a program! but it does not. Currently, it simply throws the flash[:error] message I stated in the controller that "There was a problem launching your Campaign." with no inline message specific to the program select box.
Here is the set-up..
views/campaigns/_forms.html.erb
<%= form_for #campaign, url: {action: "create"}, validate: true do |f| %>
<%= f.label :campaign_name, "Campaign Name", class: "right-label" %>
<%= f.text_field :name %>
<%= f.label :comments %>
<%= f.text_area :comment %>
<%= f.label :program %>
<%= f.select :program_id,
Program.all.collect { |p| [ p.name, p.id ] }, { include_blank: true }, validate: { presence: true } %>
<%= f.label :data_file, "Data File (.zip)", class: "right-label" %>
<%= select_tag :uploadzip_id,
options_from_collection_for_select(
Uploadzip.all, :id, :file_name
), { include_blank: "Include a Zip File" } %>
<%= f.label :additional_files %>
<ul><%= f.collection_check_boxes :uploadpdf_ids, Uploadpdf.last(5).reverse, :id,
:file_name, { mulitple: true } do |b| %>
<li><%= b.label do %>
<%= b.check_box + truncate(File.basename(b.text,'.*'), length: 45) %>
<% end %>
</ul><% end %>
<%= render 'target', :f => f %>
<%= f.submit "Confirm & Execute", id: "campaign-create-button" %>
<% end %>
views/campaigns/_target.html.erb
<%= f.label :plan, "Pick a Plan", class: "right-label" %>
<%= f.select :plan_id,
Plan.all.collect { |p|
[ p.name, p.id ]
}, { include_blank: true } %>
<%= f.label :channels, "Distribution Channel", class: "right-label" %>
<ul class="channels-list">
<% ["Folder", "Fax", "Email"].each do |channel| %>
<li><%= check_box_tag "campaign[channels][]", channel,
#campaign.channels.include?(channel),
id: "campaign_channels_#{channel}" %> <%= channel %></li>
<% end %>
</ul>
app/models/campaign.rb
class Campaign < ActiveRecord::Base
belongs_to :program
belongs_to :plan
has_many :uploadables, dependent: :destroy
has_many :uploadpdfs, through: :uploadables
has_one :uploadzip, dependent: :nullify
validates :name, presence: true,
uniqueness: true
validates :program, presence: { message: "Need a program!"}
validates :uploadzip, presence: true
validates :uploadpdf_ids, presence: true
serialize :channels, Array
end
app/controllers/campaigns_controller.rb
class CampaignsController < ApplicationController
def index
#campaigns = Campaign.all.order("created_at DESC")
end
def new
#campaign = Campaign.new
end
def create
#campaign = Campaign.new(campaign_params)
if #campaign.save
zip = Uploadzip.find(params[:uploadzip_id])
zip.campaign = #campaign
zip.save
flash[:success] = "Campaign Successfully Launched!"
redirect_to #campaign
else
flash[:error] = "There was a problem launching your Campaign."
redirect_to new_campaign_path
end
end
def show
#campaign = Campaign.includes(:program, :uploadzip, :plan, :uploadpdfs).find(params[:id])
end
private
def campaign_params
params.require(:campaign).permit(:name, :comment, :plan_id, :program_id, :campaign_id, uploadpdf_ids: [], channels: [])
end
end
I also followed this tutorial that provided code to help display validation errors for associations in the view.
config/initializers/errors_for_associations.rb
module ActionView::Helpers::ActiveModelInstanceTag
def error_message_with_associations
if #method_name.end_with?('_ids')
# Check for a has_(and_belongs_to_)many association (these always use the _ids postfix field).
association = object.class.reflect_on_association(#method_name.chomp('_ids').pluralize.to_sym)
else
# Check for a belongs_to association with method_name matching the foreign key column
association = object.class.reflect_on_all_associations.find do |a|
a.macro == :belongs_to && a.foreign_key == #method_name
end
end
if association.present?
object.errors[association.name] + error_message_without_associations
else
error_message_without_associations
end
end
alias_method_chain :error_message, :associations
end

nested forms : update child foreign key

I have a nested association:
class User < ActiveRecord::Base
has_many :hostels
accepts_nested_attributes_for :hostels
end
class Hostel < ActiveRecord::Base
belongs_to :user
end
The form :
<%= form_for #user do |f| %>
<%= f.label :email %><br>
<%= f.text_field :email %>
<% f.object.hostels << #hostel -%>
<%= f.fields_for :hostels do |ff| %>
<%= ff.hidden_field :id %>
<% end -%>
<%= f.submit %>
<% end -%>
the controller
def create
#user = User.new(user_params)
raise #user.hostels.inspect
end
private
def user_params
params.require(:user).permit(:email, hostels_attributes: [:id])
end
I would like to relink existing records of hostels to new users by updating hostel foreign key. This way, it definitly don't work.
Tried update_only: true parameter to nested too.
Any ideas about the subject or am I totally wrong about trying to do the operation like that ?
you can use a multiple select for hotels in you form, then in the controller you must require hostel_ids.
Models:
class User < ActiveRecord::Base
has_many :hostels
end
class Hostel < ActiveRecord::Base
belongs_to :user
end
Form: where :name is what you see in your multiple select
<%= form_for #user do |f| %>
<%= f.label :email %><br>
<%= f.text_field :email %>
<%= f.label "Hostels" %><br>
<%= select_tag :hotel_ids, options_for_select(Hostel.all.map{|h| [h.name, h.id]}), { :multiple => true } %>
<%= f.submit %>
<% end %>
Controller:
def create
#user = User.new(user_params)
end
private
def user_params
params.require(:user).permit(:email, hostel_ids)
end
I did not test the code but must work well.

Resources