Trying to save parameters from url into a database.
I have a link:
- #kits.each do |kit|
= link_to 'Submit Video', new_challenge_path(kit: kit)
#this will append a new parameter into the url
The link goes to a form page with this:
= simple_form_for #challenge, html: { class: "form-horizontal" } do |f|
= f.input :video_title
= f.input :video_url
= f.input :video_desc, as: :text
= f.button :submit, "Upload video"
In my controller, I have this:
def create
#challenge = Challenge.new(challenge_params)
#challenge.kit_id = params[:kit]
respond_to do |format|
if #challenge.save
format.html { redirect_to #challenge, notice: 'Challenge was successfully created.' }
format.json { render :show, status: :created, location: #challenge }
else
format.html { render :new }
format.json { render json: #challenge.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_challenge
#challenge = Challenge.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def challenge_params
params.require(:challenge).permit(:video_title, :video_url, :video_desc, :kit_id)
end
Association between kit and challenge
class Challenge < ActiveRecord::Base
belongs_to :kit, counter_cache: true
end
class Kit < ActiveRecord::Base
has_many :challenges
end
The parameter doesn't save into the :kit_id. Doesn't this: #challenge.kit_id = params[:kit] supposed to take care of saving it?
You are right to do the kit_id assignment in controller, not in the form, since doing so in the form (even by means of using the hidden field) is not secure, because changing the value of a hidden_field is just a matter of inspecting the elements of the page.
What you are doing wrong, is I assume that params[:kit] is just nil.
You would probably want to use params[:kit_id].
If that won't help, put binding.pry here:
# ... code omitted
#challenge.kit_id = params[:kit]
binding.pry
# ... code omitted
and check the value of params in opened console.
Related
I want my User to be able to change a boolean on a Share that they own, but my attempt at implementation updates the wrong record.
When I go to the show page for an Item with id:7, my controller loads the associated Share objects by looking for Shares that have item_id set to 7. When I then click the Hide or Show buttons, my code updates the associated Share's active attribute, and then redirects to that same Item.
But if I go to the show page for an Item with id:3, and click those same buttons, my code redirects to and updates the active attribute for the Share with item_id:7, instead of item_id:3. Can anyone give me an idea as to why this is happening?
My Share model:
class Share < ActiveRecord::Base
belongs_to :user
belongs_to :item
def activate
self.active = true
save
end
def deactivate
self.active = false
save
end
end
My Item model:
class Item < ActiveRecord::Base
has_many :shares
end
In my ItemsController#show action, I have this:
def show
#item = Item.friendly.find(params[:id])
#owned_share = current_user.shares.find_by(item_id: #item.id)
end
In my SharesController, I have this:
def activate
#owned_share = current_user.shares.find_by(params[:item_id])
#owned_share.activate
respond_to do |format|
format.html { redirect_to item_path(#owned_share.item) }
format.json { render :index, status: :ok, location: #owned_share }
end
end
def deactivate
#owned_share = current_user.shares.find_by(params[:item_id])
#owned_share.deactivate
respond_to do |format|
format.html { redirect_to item_path(#owned_share.item) }
format.json { render :index, status: :ok, location: #owned_share }
end
end
And in my Item show view, I have this:
<% if #owned_share.active == true %>
<div class="eight wide column">
<%= link_to "Hide", share_deactivate_path(#owned_share.item), class: "button wide-button functional-red-button", method: :post %>
</div>
<% else %>
<div class="eight wide column">
<%= link_to "Show", share_activate_path(#owned_share.item), class: "button wide-button functional-mint-button", method: :post %>
</div>
<% end %>
As stated in the comments, the param you're receiving isn't item_id, but share_id, that's why despite you modify your query adding the attribute which to look for, it doesn't give you the expected result.
Update the param which to use for getting user's share, like:
#owned_share = current_user.shares.find_by(item_id: params[:share_id])
Although in this case isn't clear why you're using share_id to look for an item_id, most probably you could update that part too.
As both actions share some specific functionality, you could make just one that just updates the active attribute "flipping" its value:
# model
def toggle_active
update(active: !active)
end
# controller
def update_active_status
#owned_share = current_user.shares.find_by(item_id: params[:share_id])
#owned_share.toggle_active
respond_to do |format|
format.html { redirect_to item_path(#owned_share.item) }
format.json { render :index, status: :ok, location: #owned_share }
end
end
It gets the current user's shares active value and alternate it by using !. Notice that if they don't have a default value, a negation of nil returns true.
!true # false
!false # true
!nil # true
Note #owned_share.active == true can also be #owned_share.active? or #owned_share.active.
Because this:
#owned_share = current_user.shares.find_by(params[:item_id])
should be:
#owned_share = current_user.shares.find_by_item_id(params[:item_id])
this is my first question on stackoverflow and I'm new to Ruby on Rails, so I'm really sorry if I'm asking the question wrong.
My problem: I have two classes (word and category) and now I try to assign several categories to one word over the variable syntactical_category, for that I use a select_tag. This works nicely, when the user creates a new word as you can see in this snippet from the command line:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"EwGk/QrOma4JGJhSBjAT6fW9BqvuCJCEPYgNC9i/okOuQZBbh1ArNEfvuHvDRwY0Q2tABYTc/b3n3tAIlQmJRg==",
"word"=>{
"name_de"=>"This is a test",
"description_de"=>"Test Description",
"syntactical_category"=>"5721e7fa8cc4b3285c000004",
"semantical_categories_ids"=>["57921a358cc4b36e42000001"]
},
"locale"=>"de"
}
But when the user tries to edit a word afterwards, the select_tag ignores the value(s) from the database and only displays the first category of all potential categories and overwrites the old value(s) if the user submits the word again. This is not what i want.
Does anybody have a solution for this problem?
I'm using Ruby 2.2.3, RubyonRails 4.2.4 and MongoDB 3.0.9, Mongoid and haml if this information helps you.
Please find below my code.
word.rb
class Word
include Mongoid::Document
include Mongoid::Attributes::Dynamic
include MultiLanguageText
belongs_to :syntactical_category, class_name: "Category", inverse_of: nil, :autosave => true
has_and_belongs_to_many :semantical_categories, class_name: "Category", inverse_of: nil, :autosave => true
field :name_de, type: String
field :name_en, type: String
field :description_de, type: String
field :description_en, type: String
end
words_controller.rb
class WordsController < ApplicationController
helper MultiLanguageText
def index
#word = Word.all
end
def show
#word = Word.find(params[:id])
end
def new
#word = Word.new
end
def create
#word = Word.new(word_params)
respond_to do |format|
if #word.save
format.html { redirect_to #word, notice: t("word_create_success") }
format.json { render :index, status: :created, location: #word }
else
format.html { render :new }
format.json { render json: #word.errors, status: :unprocessable_entity }
end
end
end
def edit
#word = Word.find(params[:id])
end
def update
#word = Word.find params[:id]
#word.update_attributes(word_params)
respond_to do |format|
if #word.update(word_params)
format.html { redirect_to #word, notice: t("word_update_success") }
format.json { render :index, status: :ok, location: #word }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def destroy
#word = Word.find(params[:id])
#word.destroy
flash[:notice] = t(:delete_confirmation)
redirect_to words_path
end
def word_params
allow = [:name_de, :name_en, :description_de, :description_en, :syntactical_category, {:semantical_categories_ids => []}]
params.require(:word).permit(allow)
end
end
words/_form.html.haml
= form_for #word do |w|
.field
.input-append
= select_tag 'word[semantical_categories_ids][]', options_for_select(Category.where(category_type: 'semantic').where(:name_de.exists => true).collect{|c| [c.name_de, c.id]})
Thank you in advance for your help!
Just pass #word.semantical_categories_ids after the collection
= select_tag 'word[semantical_categories_ids][]', options_for_select(Category.where(category_type: 'semantic').where(:name_de.exists => true).collect{|c| [c.name_de, c.id]}, #word.semantical_categories_ids)
and I think it should accept multiple values. If yes add multiple: true at the end
I think you have multiple selection select_tag
So, you have to do below
= select_tag 'word[semantical_categories_ids][]', options_for_select(YOUR_COLLECTION,ARRAY_OF_SELECTED_VALUES),{multiple: true}
Note: Add ,{multiple: true} to your select_tag
i found a solution for my problem. I'm not sure if this is "the way to do it" but for me it works fine.
- #word['semantical_categories_ids'] = [''] if !#word['semantical_categories_ids'].is_a? Array
- #word['semantical_categories_ids'].each do |entry|
= select_tag 'word[semantical_categories_ids][]', options_for_select(Category.where(category_type: 'semantic').where(:name_de.exists => true).collect{|c| [c.name_de, c.id]}, entry)
I am passing variable like that:
new_sub_request_path(request_id:#request.id)
so i get this url:
http://localhost:3000/sub_requests/new?request_id=1
In my controller i want to assign that request_id like that:
#sub_request = SubRequest.new(sub_request_params)
#sub_request.request_id = params[:request_id]
and my strong parameters are defined:
def sub_request_params
params.require(:sub_request).permit(:description, :diagnos, :price, :payment, :request_id)
end
But after save i have empty request_id attribute, so it seems that it is not assigned. What am I doing wrong?
EDIT:
Inspecting parameters in the console showed that i only have those attributes that are in my form.
EDIT2:
def create
#sub_request = SubRequest.new(sub_request_params)
#sub_request.request_id = params[:sub_request][:request_id]
respond_to do |format|
if #sub_request.save
format.html { redirect_to #sub_request, notice: 'Sub request was successfully created.' }
format.json { render :show, status: :created, location: #sub_request }
else
format.html { render :new }
format.json { render json: #sub_request.errors, status: :unprocessable_entity }
end
end
end
You have to define something like below for the request_id to save in sub_requests table.
In your create method add this line
#request = Request.find(params[:request_id]) and do
#sub_request.request_id = #request.id
or
You can just add a hidden_field in your form like below
<%= f.hidden_field :request_id, :value => #request.id %>
And make sure you are permitting :request_id in your sub_request_params
I'm trying to update an Idea attribute challenge_id through a hidden form field. Here is the field:
<%= f.hidden_field :challenge_id, :value => #challenge.id %>
It successfully passes the challenge id as a param when an idea is created to the Idea Controller#create method:
Started POST "/ideas.js" for ::1 at 2015-06-18 15:39:49 -0400
Processing by IdeasController#create as JS
Parameters: {"utf8"=>"✓", "idea"=>{"title"=>"adsf", "description"=>"asf", "domain_tokens"=>"20", "challenge_id"=>"5"}, "commit"=>"Create Idea"}
This challenge_id => 5 should then be saved to the idea in the line #idea = Idea.new(idea_params) below:
ideas_controller.rb
def create
#idea = Idea.new(idea_params)
respond_to do |format|
if #idea.save
idea_count = #idea.user.ideas_created_count
#idea.user.update(:ideas_created_count => idea_count + 1)
#idea.domains.each do |domain|
current_user.add_points(1, category: domain.title)
end
#ideas = current_user.current_team.ideas.sort_by{|i| i.heat_index}.reverse
#ideas = #ideas.paginate(:page => params[:ideas_page], :per_page => 10)
format.html { redirect_to :back, notice: 'Idea was successfully created.' }
format.json { render :show, status: :created, location: #idea }
format.js
else
format.html { redirect_to :back, notice: "You must attach domains to your Idea." }
format.json { render json: #idea.errors, status: :unprocessable_entity }
format.js { render :create_failed }
end
end
end
.
.
def idea_params
params.require(:idea).permit(:title, :description, :challenge_id)
end
However, this challenge id isn't being saved to the idea with the other permitted idea_params, :title and :description. How can I get challenge_id to be saved to the Idea when it's created?
Instead of using hidden field, why not pass in the challenge_id in your form? Otherwise, you leave open the possibility that users can enter whatever they want in that hidden field.
Form:
form_for [#challenge, Idea.new] do |f|
And then:
def create
#challenge = Challenge.find(params[:challenge_id])
#idea = Idea.new(idea_params)
#idea.challenge_id = #challenge.id
end
I'm assuming you have challenge_id column in ideas table.
Try something like:
def create
#idea = Idea.new(idea_params)
#idea.challenge_id = params[:idea][:challenge_id]
#...
end
If you params or column you want to save it to is different, make sure to make the change, but you get the idea.
I have a Client model with the following line:
has_many :payments
and a Payments model with:
belongs_to :client
and
def generate_sepa
sdd = SEPA::DirectDebit.new(
name: 'name',
bic: 'bic',
iban: 'iban',
creditor_identifier: 'identifier'
)
SDD.add_transaction(
name: #client.company,
bic: #client.bic,
iban: #client.iban,
amount: self.amount,
reference: self.payment_reference,
remittance_information: self.remittance_information,
mandate_id: self.mandate_id,
mandate_date_of_signature: self.mandate_date_of_signature,
local_instrument: 'CORE',
sequence_type: self.sequence_type,
requested_date: self.date_of_payment,
batch_booking: self.batch_booking,)
sdd.to_xml
end
In payments show view I have
<%= #payment.generate_sepa %>
and in payments controller
def show
#client = Client.find(:id => params[:client_id])
end
Unfortunately I get the following error:
Unknown key: id
for
#client = Client.find(:id => params[:client_id])
In clients controller I also have:
def client_params
params.require(:client).permit(:id, :trading_name, :company_name, :owner, :main_contact_name,
:email, :phone, :date_joined, :trading_street_one, :trading_street_two, :trading_town, :trading_county, :iban, :bic)
end
and in payments:
def payment_params
params.require(:payment).permit(:client_id, :signup_fee, :monthly_fee, :date_of_payment, :payment_reference,
:remittance_information, :mandate_id, :mandate_date_of_signature, :batch_booking, :sequence_type, :is_recurring, :is_onceoff)
end
Is there an issue with the way I've whitelisted id? Or is there something wrong with the association between client and payments because, to be honest, I'm having a tough time figuring out what's going wrong.
EDIT
:client_id gets passed to payments like so when I create a new client:
def create
#client = Client.new(client_params)
respond_to do |format|
if #client.save
format.html { redirect_to new_payment_url(:client_id => #client.id) }
format.json { render action: 'show', status: :created, location: #client }
else
format.html { render action: 'new' }
format.json { render json: #client.errors, status: :unprocessable_entity }
end
end
end
in the payments _form partial I also have:
<%= f.hidden_field('client_id', :value => params[:client_id]) %>
along with the rest of the form fields.
In payment controller/show #client = Client.find(params[:id]) will not work.
Use
#payment= Payment.find(params[:id])
#client = #payment.client
Because you are passing payment id to the show, not the client id.
def show
#client = Client.find(params[:client_id])
end
Isn't it?