I have a site where uses have a profile and can add an art to their profile and the month_started, year_started, and rank in that art. I am able to add the art but I cannot get update to work. I'm doing it from within the users folder on the show page. I render the add_art form on the profile page and it submits to the user_arts_controller's create action. For edit_art I am trying to use the edit.html.erb page inside users and it pulls in the information from the #art_user table to populate the fields, but when I submit it acts like it's updating and goes back to the set page and gives a success message but nothing gets updated. I used byebug and it shows all the params but says permitted: false.
Here is my form:
<% vars = request.query_parameters %>
<% #add = vars['add'] %>
<% if #add == "1" %>
<% art = "Judo" %>
<% else %>
<% art = "Brazillian Jiu Jitsu" %>
<% end %>
<div class="container">
<div class="row center form">
<div class="col-sm-12 col-md-10">
<div class="card-panel">
<h3>Edit <%= art %> info.</h3>
<%= form_with(model: #art, url: art_edit_path(art_id: #add), class: "shadow p-3 mb-3 rounded text-dark", local: true) do |f| %>
<div class="form-group row">
<div class="col-md-3 col-sm-12 col-form-label">
<%= f.label :month_started %>:<span class="text-danger">*</span>
</div>
<div class="col-md-9 col-sm-12">
<%= f.select :month_started, Date::MONTHNAMES[1..12], {prompt: true}, {class: 'form-control'} %>
</div>
</div>
<diva class="form-group row">
<div class="col-md-3 col-sm-12 col-form-label">
<%= f.label :year_started %>:<span class="text-danger">*</span>
</div>
<div class="col-md-9 col-sm-12">
<%= f.select :year_started, Date.today.year-70 .. Date.today.year, {prompt: true, order: [:year]}, {class: 'form-control'} %>
</div>
</diva>
<% #rank = Rank.where(art_id: #add) %>
<div class="form-group row">
<div class="col-md-3 col-sm-12 col-form-label">
<%= f.label :rank %>:<span class="text-danger">*</span>
</div>
<div class="col-md-9 col-sm-12">
<%= f.collection_select :rank_id, #rank, :id, :rank, {:prompt=>true}, {:class=>'form-control'} %>
</div>
</div>
<div class="form-group row text-right">
<div class="col-md-8 col-sm-12"></div>
<div class="col-md-4 col-sm-12">
<%= f.submit (#add == "1" ? "Edit Judo" : "Edit Brazilian Jiu Jitsu"), class: "profile_btn" %>
</div>
</div>
<% end %>
</div>
</div>
</div>
</diva>
Here is the user_arts_controller.rb:
class UserArtsController < ApplicationController
def create
art_to_add = Art.find(params[:art_id])
unless current_user.arts.include?(art_to_add)
UserArt.create(art: art_to_add, user: current_user, month_started: params["month_started"], year_started: params["year_started"], rank_id: params["rank_id"])
flash[:notice] = "You have successfully enrolled in #{art_to_add.art}"
redirect_to ("/users/#{current_user.username}?cat=comp")
else
flash[:notice] = "Something went wrong!"
redirect_to ("/users/#{current_user.username}")
end
end
def edit
#art = UserArt.find_by(user_id: current_user.id, art_id: 1)
if #art
#my_rank = Rank.find(id: #art.rank_id)
end
end
def update
byebug
#user_art = UserArt.where(id: params[:id])
if #user_art.update(art_params)
flash[:notice] = "You have successfully updated your art"
redirect_to ("/users/#{current_user.username}?cat=comp")
else
flash[:notice] = "Something went wrong!"
redirect_to ("/users/#{current_user.username}")
end
end
private
def art_params
params.require(:user_arts).permit(:user_id, :art_id, :month_started, :year_started, :rank_id)
end
end
Here are my routes:
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: 'registrations', omniauth_callbacks: 'users/omniauth_callbacks' }
root 'pages#index'
get 'events', to: 'pages#events'
get 'features', to: 'pages#features'
get 'pricing', to: 'pages#pricing'
get 'about', to: 'pages#about'
get 'contact', to: 'pages#contact'
get 'privacy', to: 'pages#privacy'
get 'terms', to: 'pages#terms'
get 'remove', to: 'pages#remove'
delete 'logout', to: 'sessions#destroy'
resources :users, except: [:new], param: :username
resources :clubs, param: :club_username
post 'club_join', to: 'user_clubs#create'
post 'art_add', to: 'user_arts#create'
post 'art_edit', to: 'user_arts#edit'
patch 'art_edit', to: 'user_arts#update'
end
Here is what I get when I use byebug and enter params:
(byebug) params
<ActionController::Parameters {"_method"=>"patch", "authenticity_token"=>"UY4RG1D0N0IHcJeyftn44WmAgsdslKJScD+GSJPbAUEEjlJLiYLd2htK4RBTfrP+YPUXP5EFB5pQc98OmQPPtg==", "user_art"=>{"month_started"=>"January", "year_started"=>"1988", "rank_id"=>"14"}, "commit"=>"Edit Judo", "art_id"=>"1", "controller"=>"user_arts", "action"=>"update"} permitted: false>
(byebug)
Any help is greatly appreciated.
Thanks
I think you have an extra s in the definition of your allowed params. Since you are getting this:
"user_art"=>{"month_started"=>"January", "year_started"=>"1988", "rank_id"=>"14"}
You should check in this way:
def art_params
params.require(:user_art).permit(:user_id, :art_id, :month_started, :year_started, :rank_id)
end
Just a final comment. Take a look at the params you're permitting, I guess user_id shouldn't be one of them.
Let me know if it works
Related
I am trying to make a nested form with two types of movements: mov_principal and mov_egreso, of which I try it through a main movement
these are the models
mov_principal.rb
class MovPrincipal < ActiveRecord::Base
self.table_name = 'mov_principal'
has_one :mov_ingreso, :class_name => 'MovIngreso'
accepts_nested_attributes_for :mov_ingreso
belongs_to :tipo_concepto, :class_name => 'TipoConcepto', :foreign_key => :id_tipo
belongs_to :banco
end
mov_ingreso
class MovIngreso < ActiveRecord::Base
self.table_name = 'mov_ingreso'
belongs_to :mov_principal , :class_name => 'MovPrincipal'
accepts_nested_attributes_for :mov_principal, :allow_destroy => true
has_many :puntos, :class_name => 'Punto'
end
the controller mov_principal_controller.rb
class MovPrincipalsController < ApplicationController
before_action :set_movprincipal, except: [:index,:new,:create]
before_action :set_tipooper
def index
#mov_principals = MovPrincipal.all.order("referencia DESC")
end
def new
#mov_principal = MovPrincipal.new
if params[:tipooper] == '0'
#mov_ingreso = #mov_principal.build_mov_ingreso
else
# #gastos = Gasto.new
# #mov_egresos = #mov_principal.build_mov_egresos
#mov_egresos = #mov_principal.mov_egresos.build
#gasto = #mov_egresos.build_gasto
end
end
def create
if #tipooper == '0'
#mov_principal = current_user.mov_principals.new(movingreso_params)
else
#mov_principal = current_user.mov_principals.new(movgastos_params)
end
if #mov_principal.save
render :show
else
render :new
end
end
private
def set_movprincipal
#mov_principal = MovPrincipal.find(params[:id])
end
def set_tipooper
#tipooper = params[:tipooper]
end
def movgastos_params
params.require(:mov_principal).permit(:id,:referencia,:id_tipo,:banco_id,
mov_egreso_attributes: [:id,:mov_principal_id,:haber, :gasto_id,
gasto_attributes: [Gasto.attribute_names.map(&:to_sym).push(:_destroy)]] )
end
def movingreso_params
params.require(:mov_principal).permit(:id,:referencia,:id_tipo,:banco_id,:user_id,:_destroy,
mov_ingreso_attributes: [:id,:debe,:mov_principal_id,:_destroy ])
end
end
And the view
_formingreso.html.erb
<%=form_for(#mov_principal, :html => {:class => 'form-horizontal'}) do |f| %>
<% #mov_principal.errors.full_messages.each do |message| %>
<div class="be-red white top-space">
* <%= message %>
</div>
<% end %>
<div class="form-group row">
<label class="col-sm-2 col-form-label"> <%= f.label :referencia, "N° Referencia" %> </label>
<div class="col-sm-10">
<%= f.text_field :referencia, class: 'form-control', placeholder: "N° DE REFERENCIA" %>
</div>
</div>
<div class="form-group row" >
<label class="col-sm-2 col-form-label"> <%= f.label :id_tipo, "Tipo" %> </label>
<div class="col-sm-10">
<%= f.collection_select(:id_tipo, TipoConcepto.where(:forma => "1"), :id, :tipo,{:prompt => "SELECCIONE EL TIPO DE INGRESO"}, {class: 'custom-select'}) %>
</div>
</div>
<div class="form-group row" >
<label class="col-sm-2 col-form-label"> <%= f.label :id_banco, "Banco" %> </label>
<div class="col-sm-10">
<%= f.collection_select(:banco_id, Banco.all, :id, :nombre,{:prompt =>"SELECCIONE EL BANCO"} ,{class: 'custom-select'} ) %>
</div>
</div>
<div class="form-group row" >
<%= f.fields_for :mov_ingreso_attributes do |ingreso| %>
<label class="col-sm-2 col-form-label"> <%= ingreso.label :debe, "Monto" %> </label>
<div class="col-sm-10">
<%= ingreso.text_field :debe, class: 'form-control' , placeholder: "MONTO DE INGRESO" %>
</div>
<% end %>
The page loads me, it saves me the mov_principal data but it does not save me the mov_ingreso data and the error I find in the console is Unpermitted parameter: :mov_ingreso_attributes
Please do not send me links from the official rails page on how to work strong_parameter blah blah blah I have hours researching and searching in forums trying solutions and even read in a blog about an error that has rails when updating version, and had to create a initializer of strong_parameter, I did it and nothing anyway I show it here just in case it has any relevance
/initializers/strong_parameter.rb
if Rails.env.test?
ActionController::Parameters.action_on_unpermitted_parameters = :raise
end
Thank you all!!
in Main form
<%= p.fields_for :prd_allisland_flat_deliveries do |i| %>
<%= render(:partial => 'prd_allisland_flat_delivery_field', :locals => {:f => i})%>
<% end %>
in the prd_allisland_flat_delivery_field form partial
<div class="row" style="padding-bottom: 25px">
<div class="col-md-2"></div>
<div class="col-md-4">
<%= f.label :delivery_period %>
</div>
<div class="col-md-4">
<%= f.text_field(:delivery_period, {placeholder: '0', class: 'form-control input_border input_field_text_align_right'})%>
</div>
<div class="col-md-2"></div>
</div>
<div class="row" style="padding-bottom: 25px">
<div class="col-md-2"></div>
<div class="col-md-4">
<%= f.label :delivery_rate %>
</div>
<div class="col-md-4">
<%= f.text_field(:delivery_rate, {placeholder: 'Rs. 0.00', class: 'form-control input_border input_field_text_align_right'})%>
</div>
</div>
in prd_item controller
**def new
#item = PrdItem.new
#item.build_prd_allisland_flat_delivery
end**
after writing this the create method
**
if #item.save
if #item.delivery_type == 1
#all_island_flat = PrdAllislandFlatDelivery.new(item_params[:prd_allisland_flat_deliveries_attributes])
#all_island_flat.save
end
end**
the item_params
def item_params
params.require(:prd_item).permit(:item_name, :brand, :item_no, :short_description, :long_description, :prd_type_id, :usr_vendor_property_id, :price,:base_price, :price_discount, :percentage_discount, :stock_count, :availability, :tags, :remove_image, :delivery_type , :min_stock_count,
prd_item_images_attributes: [:id, :image, :description, :link, :_destroy ],
prd_temp_variation_stores_attributes: [:id, :product_variations, :variation_items, :_destroy],
prd_temp_compound_stores_attributes:[:id,:compound, :compound_item, :_destroy],
prd_temp_spec_stores_attributes:[:id,:compound, :compound_item, :_destroy],
prd_allisland_flat_deliveries_attributes: [:id,:delivery_period,:delivery_rate],
prd_province_vise_deliveries_attributes: [:id , :province_name , :delivery_rate, :delivery_period]
)
end
the rails consoler gets the attributes for the prd_allisland_flat_deliveries but the prd_all_island_flat_deliveries fill with null values
Is that your full create method? If so you need to understand that every request is separate from others, the create request doesn't know what happened in the new request.
In your create method you need to build your basic object, then update the object from the params.
def create
#item = PrdItem.new
#item.update(item_params)
if #item.save ...
I am trying to create two associated objects from two different models but I am still getting the same error "param is missing or the value is empty: repost" I have tried to figure out why it fails for days but in vain. Any hint?
I have the Model repost
class Repost < ApplicationRecord
has_many :recurrences, inverse_of: :repost
accepts_nested_attributes_for :recurrences
def self.create_repost (twit_id)
twit = Twit.find_by_id(twit_id)
Repost.find_or_create_by(link: twit.link) do |repost|
repost.twit_id = twit.id
repost.content = twit.content
repost.image_url = twit.image_url
repost.content_url = twit.content_url
repost.click = 0
repost.like = 0
repost.retweet = 0
repost.engagement = 0
repost.number_of_publications = repost.publications.count
repost.likes_sum = 0
repost.retweets_sum = 0
repost.engagement_sum = 0
repost.recurrence = repost.recurrences.recurring
end
end
and the model Recurrence
class Recurrence < ApplicationRecord
serialize :recurring, Hash
belongs_to :repost, inverse_of: :recurrences
def self.set(repost_id, frequency)
repost = Repost.find_by_id(repost_id)
Recurrence.create do |recurrence|
recurrence.repost_id = repost.id
recurrence.recurring = frequency
recurrence.start_time = recurrence.created_at
recurrence.end_time = nil
end
end
def recurring=(value)
if RecurringSelect.is_valid_rule?(value)
super(RecurringSelect.dirty_hash_to_rule(value).to_hash)
else
super(nil)
end
end
def rule
rule = IceCube::Rule.from_hash(self.recurring)
rule
end
def schedule
schedule = IceCube::Schedule.new(self.created_at)
schedule.add_recurrence_rule(rule)
schedule
end
end
here is my Repost Controller
class RepostsController < ApplicationController
before_action :find_repost, only: [:show, :edit, :update, :destroy, :get_likes]
def index
#repost = Repost.new
if params[:filter_by]
#reposts = Repost.filter(params[:filter_by], params[:min], params[:max], params[:start_at], params[:end_at])
else
#reposts = Repost.all.order("created_at DESC")
end
end
def show
end
def new
#repost = Repost.new
end
def create
#repost = Repost.create_repost(repost_params)
redirect_to reposts_path
end
def destroy
#repost.destroy
redirect_to reposts_path
end
private
def find_repost
#repost = Repost.find(params[:id])
end
def repost_params
params.require(:repost).permit(:twit_id, recurrences_attributes: [:recurring])
end
end
and here is my view with the form
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-sm-offset-1">
<h1 class="twit-h1">My best Tweets</h1>
<p><%= render "filter_form" %></p>
<p><% #twits.each do |twit| %></p>
<p><%= form_for #repost do |f| %></p>
<%= hidden_field_tag :twit_id , twit.id %>
<div class="twit">
<%= image_tag "#{twit.image_url}", class: "twit-image" %>
<div class="twit-body">
<% if twit.content.present? %>
<h3><%= twit.content %></h3>
<% else %>
<%= "This tweet has no text" %>
<% end %>
<% if twit.content_url.present? %>
<%= link_to "#{twit.content_url}".truncate(40), twit.content_url, class: "twit-link" %>
<% else %>
<%= "This tweet has no link" %>
<% end %>
<%= f.fields_for :recurrences do |r| %>
<h6 style="float: right;"><%= r.select_recurring :recurring %></h6>
<% end %>
<h6>
<i class="fa fa-bullhorn fa" aria-hidden="true"></i> <%= twit.engagement %>
<i class="fa fa-retweet fa" aria-hidden="true"></i> <%= twit.retweet %>
<i class="fa fa-heart fa" aria-hidden="true"></i> <%= twit.like %>
</h6>
<p>Tweeted on <%= (twit.first_date).strftime("%A, %B %d, %Y at %I:%M%p %Z") %></p>
<%= link_to "Delete", twit_path(twit), name: nil, class: "btn btn-danger btn-sm", method: :delete, data: {:confirm => 'Are you sure?'} %>
<%= f.submit "Add to your Reposts library", class: "btn btn-primary btn-sm" %>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
</div>
Update, here is my logs
Started POST "/__better_errors/923b59f8da1318ef/variables" for ::1 at 2017-02-21 15:52:56 +0100
Started POST "/reposts" for ::1 at 2017-02-21 15:54:14 +0100
Processing by RepostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"62pE3le5m99HF10RgQcd70wFHqWQWiRmQQO2ndNHT3gnceRu94Y1ttyBuSExBjr4/cxeVUtgY60GRThxdpFGJg==", "twit_id"=>"1844", "recurring"=>"{\"interval\":1,\"until\":null,\"count\":null,\"validations\":{\"day\":[1],\"hour_of_day\":1,\"minute_of_hour\":0},\"rule_type\":\"IceCube::WeeklyRule\",\"week_start\":0}", "commit"=>"Add to your Reposts library"}
Completed 400 Bad Request in 2ms (ActiveRecord: 0.0ms)
ActionController::ParameterMissing - param is missing or the value is empty: repost:
It seems my error comes from this private method in my Repost controller but I can't understand why?
def repost_params
params.require(:repost).permit(:twit_id, recurrences_attributes: [:recurring])
end
Thank you!
before I ask my question, I will provide some context.
I have 3 Models which interact with each other.
Scoreboard has many Teams. Team belongs to Scoreboard.
The following use a through table.
Scoreboard many-to-many with User.(let's call this Scoreboard.followers)
Team many-to-many with User.(Let's call this Team.members)
I have a Team_Members Controllers with the following method:
Team_member#new Method:
def new
#selected = true
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#team = Team.find(params[:team_id])
#team_members = #team.members
#followers = #scoreboard.followers.search(params[:search]).paginate(page: params[:page], per_page: 50)
end
What I'm attempting to do is display all the Scoreboard followers in my new.html.erb view. I can search through them and add members to a Team that is associated to the same Scoreboard.
Here's is the new.html.erb view:
<%= form_tag(new_scoreboard_team_team_member_path, :method => "get", id: "member-search-form", autocomplete: "off") do %>
<div class="row new-member-field">
<div class="col-xs-12 col-sm-6">
<%= text_field_tag :search, params[:search], placeholder: "Filter Members by Name", class:"form-control" %>
</div>
</div>
<% end %>
<% if #followers.any? %>
<% #followers.each do |follower| %>
<div class="row member-follower-div" id="follower_<%=follower.id%>">
<div class="col-xs-10 col-sm-5 member-prof-link">
<%= link_to follower.name, user_path(follower.id) %>
</div>
<div class="col-xs-2 col-sm-1 member-add">
<%= link_to (add_scoreboard_team_team_member_path(#scoreboard,#team, follower)), method: :post, remote: true, :data => {:disable_with => ".."} do %>
<i class="fa fa-plus-square fa-lg" aria-hidden="true"></i>
<% end %>
</div>
</div>
<% end %>
<div class="row">
<div class="col-xs-12 col-sm-6 new-member-pages">
<%= will_paginate #followers %>
</div>
</div>
<% end %>
Okay now for the question. The problem arises in the controller method. The #team.members and #scoreboard.followers both source objects from the Users table. How would I filter out the User objects from the #scoreboard.followers that exist in the #team.members? I don't want to display #followers on my view that are a part of the #team.members collection. Also, as a bonus, I would like to alphabetically order the followers by user.name.
I tried the .where("users.id NOT IN (?)", #team_members.pluck(:id)) but if #team_members collection is null, no results are displayed on the page.
I solved it like so:
def new
#selected = true
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#team = Team.find(params[:team_id])
#team_members = #team.members
if (#team_members.any?)
#wonderful_humans = #scoreboard.favourited_by.where("users.id NOT IN (?)", #team_members.pluck(:id)).search(params[:search]).sort_by{ |a| a.name.downcase }
else
#wonderful_humans = #scoreboard.favourited_by.search(params[:search]).sort_by{ |a| a.name.downcase }
end
#followers = #wonderful_humans.paginate(page: params[:page], per_page: 50)
end
I have been trying to setup pagination properly but I am having trouble following any tutorial and getting it to work properly.
What I basically want setup is that when a user chooses the number of companies they want to appear on a page, the following loop with paginate the given number of companies on each page. If the user doesn't choose a specific number of companies/page, there would be a default value that would be set.
If anyone could maybe give me a push in the right direction, that would be much appreciated.
View
<ul class="list-group">
<%= #comps.find_each do |comp| %>
<li class="list-group-item">
<div class="row">
<div class="span12">
<p style="font-size: 1.5em"><strong><%= link_to comp.name, comp %></strong></p>
<hr class="divider">
<div class="row">
<div class="span6">
<p><strong>Primary Field:</strong> <%= comp.primary_field %></p>
<p><strong>Description:</strong> <%= truncate(comp.description, length: 150) { link_to "Read More", comp, :target => "_blank"}%>
</p>
</div>
<div class="span5">
<% if signed_in? %>
<p><% if !(current_user.favorites.include? comp) %>
<%= link_to 'Favorite',
favorite_company_path(comp, type: "favorite"),
class: "btn btn-primary",
method: :put%>
<% else %>
<%= link_to 'Unfavorite',
favorite_company_path(comp, type: "unfavorite"),
class: "btn btn-danger",
method: :put%>
<% end %></p>
<% end %>
<p><strong>Website:</strong> <%= auto_link(comp.website, :html => { :target => '_blank' })%></p>
<p><strong>Location:</strong> <%= comp.address %></p>
</div>
</div>
</div>
</div>
</li>
<% end %>
<%= will_paginate #comps%>
</ul>
Controller (Where the list page is handled)
def filter
if ((params[:field] != "") and (params[:field] != "All Fields") and (params[:field] != nil))
# This will apply the filter
#comps = Company.where(primary_field: params[:field])
else
# This will return all records
#comps = Company.all
end
end
def list
#fields = ##primary_field
filter
#comps = #comps.paginate(:page => params[:page], :per_page => params[:number_of_companies] ||= 5)
end
Model for the list page
class DynamicPages < ActiveRecord::Base
self.per_page = 5
end
Since you are using will_paginate. You could do in this way.
Post.paginate(:page => params[:page], :per_page => params[:number_of_companies] ||= 10)
Here params[:number_of_companies] is the number of companies a user has selected and 10 is the
default page value.
class Post
self.per_page = 10
end
Also, your code snippet <%= #comps.find_each do |comp| %>, should be this <% %> instead of <%= %>