Rails 5 Carrierwave - Strong Param exists but nil in hash - carrierwave

I have applications table with attachment field which is a file uploaded by carrierwave. I'm using SQLLite. Upon application form submit, in #create
#application = Application.new(application_params)
#application contains attachment as nil.
Interestingly,
params[:attachment] is nil also but params[:application][:attachment] = 'valid/path/of/file' and application_params is also 'same/valid/path/of/file'.
As a result #application cannot be saved as I cannot save without attachment. It has suddenly started and I cannot figure out. Can anyone please advise. TIA. #create action upto save:
def create
#application = Application.find_by_user_id_and_type_id(params[:application][:user_id], params[:application][:type_id])
if params[:application][:attachment].nil? || params[:application][:attachment].blank?
flash[:notice] = "You have to add an attachment of type - .doc/.docx/.pdf/.txt/.rtf."
end
if #application.nil?
#application = Application.new(application_params)
if #application.save
Here's the browser output from submit.
{"utf8"=>"✓","authenticity_token"=>"egFav9RYAOXJQ==","application{"user_=>"109", "type_id"=>"4", "years_of_experience"=>"", "attachment"=>"/uploads/data_attachment/attachment/93/Steps_to_be_done.docx", "message"=>""},"commit"=>"Submit"}
Now a little hack I did today morning that 'forced' it to work for sometime.Not sure, why it worked then and not now.
def application_params
params.require(:application).permit(:user_id, :type_id, :message, :years_of_experience, :attachment)
if params[:attachment].nil?
params.fetch(:application).permit(:user_id, :type_id, :message, :years_of_experience, :attachment)
end

Related

Update a file variable (Active Storage)

I'm using ActiveStorage (which is great !) to manage files in my app. An admin have to validate all the submits. So to solve that, I added a new column validated into the ActiveStorageBlob table. As I can define if the file is validated or not by the admin.
But my problem is that I cannot update this value. But I can ask the value of this variable.
def upd_val
#photo = current_user.photo
if #photo.validated?
#photo.update(validated: true)
else
#photo.update(validated: false)
end
end
you can do something like that :
def upd_val
#photo = current_user.photo
#photo_id = #photo.id
if #photo.validated?
ActiveStorage::Blob.find(#photo_id).update(validated: true)
else
ActiveStorage::Blob.find(#photo_id).update(validated: false)
end
end

what var type to dynamically access Model's attribute from another controller? (Rails 4.2)

Goal: dynamically update another Model's properties (Tracker) from Controller (cards_controller.rb), when cards_controller is running the def update action.
Error I receive : NameError in CardsController#update, and it calls out the 2nd last line in the
def update_tracker(card_attribute) :
updated_array = #tracker.instance_variable_get("#{string_tracker_column}")[Time.zone.now, #card.(eval(card_attribute.to_s))]
Perceived problem: I have everything working except that I don't know the appropriate way to 'call' the attribute of Tracker correctly, when using dynamic attributes.
The attribute of the Tracker is an array (using PG as db works fine), I want to
figure out what property has been changed (works)
read the corresponding property array from Tracker's model, and make a local var from it. (works I think, )
push() a new array to the local var. This new array contains the datetime (of now) and, a string (with the value of the updated string of the Card) (works)
updated the Tracker with the correct attribute.
With the following code from the cards_controller.rb
it's the if #card.deck.tracked in the update method that makes the process start
cards_controller.rb
...
def update
#card = Card.find(params[:id])
if #card.deck.tracked
detect_changes
end
if #card.update_attributes(card_params)
if #card.deck.tracked
prop_changed?
end
flash[:success] = "Card info updated."
respond_to do |format|
format.html { render 'show' }
end
else
render 'edit'
end
end
...
private
def detect_changes
#changed = []
#changed << :front if #card.front != params[:card][:front]
#changed << :hint if #card.hint != params[:card][:hint]
#changed << :back if #card.back != params[:card][:back]
end
def prop_changed?
#changed.each do |check|
#changed.include? check
puts "Following property has been changed : #{check}"
update_tracker(check)
end
end
def update_tracker(card_attribute)
tracker_attribute = case card_attribute
when :front; :front_changed
when :back; :back_changed
when :hint; :hint_changed
end
string_tracker_column = tracker_attribute.to_s
#tracker ||= Tracker.find_by(card_id: #card.id)
updated_array = #tracker.instance_variable_get("#{string_tracker_column}")[Time.zone.now, #card.(eval(card_attribute.to_s))]
#tracker.update_attribute(tracker_attribute, updated_array)
end
Edit: For clarity here's the app/models/tracker.rb:
class Tracker < ActiveRecord::Base
belongs_to :card
end
Your use of instance_variable_get has been corrected, however this approach is destined to fail because ActiveRecord column values aren't stored as individual instance variables.
You can use
#tracker[string_column_changed]
#card[card_attribute]
To retrieve attribute values by name. If you want to get an association, use public_send. The latter is also useful if there is some accessor wrapping the column value (eg carrierwave)
From your error it seem your issue is this:
#tracker.instance_variable_get("#{string_tracker_column}")
evaluates to this after string interpolation:
#tracker.instance_variable_get("front_changed")
which is incorrect use of instance_variable_get. It needs an # prepended:
#tracker.instance_variable_get("#front_changed")
Seems like using instance_variable_get is unnecessary, though, if you set attr_reader :front_changed on the Tracker model.

No server response

I really can't find the solution for this. I'm trying to access a game API to fill platform (PS3 Xbox) information for the games I insert manually. All information about the game that I have (like the name of the game) is in strong params. So I use the name that I inserted manually to get platform using the API.
When I try the first example, things works just well, but the second example, I got no answer from the server. Nothing happens when I submit to the create action, not a single line on server logs :-/
The only difference between the examples is the way I save game's name to make the API request. I'm using Nokogiri Gem to parse API's XML and the code looks fine to me.
Can you help me?
Thanks,
Example 1 (works well):
def create
#game = Game.new(game_params)
firstUrl = "http://thegamesdb.net/api/GetGamesList.php?name=sonic"
# I'm hardcoding a game just for debug
gameList = Nokogiri::XML(open(firstUrl))
gameApiId = gameList.css("Game id").first.text
secondUrl = "http://thegamesdb.net/api/GetGame.php?id=" + gameApiId
gameInformation = Nokogiri::XML(open(secondUrl))
#game.platform = gameInformation.xpath("//Game//Platform").text
if #game.save
redirect_to #game, notice: 'Game was successfully created.'
else
render :new
end
end
private
def game_params
params.require(:game).permit(:name, :publisher, :year, :description, :image, levels_attributes: [:id, :name, :sort_order, :_destroy])
end
Example 2 (no response from server)
def create
#game = Game.new(game_params)
firstUrl = "http://thegamesdb.net/api/GetGamesList.php?name=" + #game.name.gsub(/\s+/, "")
# I'm hardcoding a game just for debug
gameList = Nokogiri::XML(open(firstUrl))
gameApiId = gameList.css("Game id").first.text
secondUrl = "http://thegamesdb.net/api/GetGame.php?id=" + gameApiId
gameInformation = Nokogiri::XML(open(secondUrl))
#game.platform = gameInformation.xpath("//Game//Platform").text
if #game.save
redirect_to #game, notice: 'Game was successfully created.'
else
render :new
end
end
private
def game_params
params.require(:game).permit(:name, :publisher, :year, :description, :image, levels_attributes: [:id, :name, :sort_order, :_destroy])
end
In summary, the difference is this:
firstUrl = "http://thegamesdb.net/api/GetGamesList.php?name=" + #game.name.gsub(/\s+/, "")
What you're going to get on here are tips on how to debug this issue. The problem is since you're pinging a third-party API, we have scant information on what the returned data is meant to be like, making any "solution" a case of stabbing in the dark
--
Debug
I would do several things:
Make sure this new link is accessible & returns data
Make sure the rest of the variables & data is intact
Ensure the third party API is able to provide the return you want
I suspect the issue will be with the way you're calling #game.name.gsub - have you confirmed this is indeed being called?
I just tested the url http://thegamesdb.net/api/GetGamesList.php?name=StarFox and it brought back data. Upon initial insepction, I would suspect the crux of the issue is with your calling of this url

Strong parameters in test issue

Ruby 2.1.1p76 on Rails 4.1.1.
Please check out my controller:
def update
begin
current_user.update_settings user_settings_params unless params[:user_setting].blank?
current_user.update_attribute :district_id, params[:user][:district_id] unless params[:user].blank? || params[:user][:district_id].blank?
flash[:success] = "Preferencje zostały zaktualizowane"
redirect_to subscription_index_path
rescue UserLevelException => exception
flash[:alert] = "Sprytnie, za karę zostałeś wylogowany ;)"
session[:user_id] = nil
redirect_to root_path
return
end
end
private
def user_settings_params
params.require(:user_setting).permit(
:inquiry_subject, :inquiry_body,
:offer_subject, :offer_body,
:only_companies_with_email,
{:district_ids => []},
# {:district_ids => params[:user_setting][:district_ids].try(:keys)},
:delivery_address,
)
end
See the commented line? In the form above - user_settings_params will not return :district_ids array of ids, and this is fine, since I can use the line below instead to have them (got it from guides).
The problem I have is when running this test:
test 'should set user level10 districts' do
user = login_user :paid10
post :update, :user_setting => {:district_ids => [districts(:zachodniopomorskie).id, districts(:slaskie).id]}
assert_equal nil, flash[:alert]
assert_equal 'Preferencje zostały zaktualizowane', flash[:success]
db_user_districts = User.find(user.id).settings.districts.all
assert db_user_districts.include? districts(:zachodniopomorskie)
assert db_user_districts.include? districts(:slaskie)
assert_equal 2, db_user_districts.count
end
It passes. When debugging user_settings_param has :district_ids available as if strong parameters were disabled or something. I wanted to submit an issue to rails but most probably I'm doing something wrong and can't figure it out.
I've found it - it was because of quirky way I was creating checkboxes for HABTM
= check_box_tag "user_setting[district_ids][#{district.id}]", district.id, user.settings.district_ids.include?(district.id)
= label_tag "user_setting[district_ids][#{district.id}]", district.name
For no particular reason I've inserted ids into params keys AND values. And because of that those were passed to params object as hash. In test though those were sent as array. So it was the view to blame.
= check_box_tag "user_setting[district_ids][]", district.id, user.settings.district_ids.include?(district.id)
= label_tag "user_setting[district_ids][]", district.name

Rails 3.0.7 ActionMailer attachment issue

I'm trying to attach a file to an outgoing email but the attachment size ends up being 1 byte. It doesn't matter what attachment I'm forwarding it always ends up in the email 1 byte in size (corrupt). Everything else looks ok to me.
The email information is pulled from an IMAP account and stored in the database for browsing purposes. Attachments are stored on the file system and it's file name stored as an associated record for the Email.
In the view there's an option to forward the email to another recipient. It worked in Rails 2.3.8 but for Rails 3 I've had to change the attachment part of the method so now it looks like...
def forward_email(email_id, from_address, to_address)
#email = Email.find(email_id)
#recipients = to_address
#from = from_address
#subject = #email.subject
#sent_on = Time.now
#body = #email.body + "\n\n"
#email.attachments.each do |file|
if File.exist?(file.full_path)
attachment :filename => file.file_name, :body => File.read(file.full_path)
else
#body += "ATTACHMENT NOT FOUND: #{file.file_name}\n\n"
end
end
end
I've also tried it with...
attachments[file.file_name] = File.read(file.full_path)
and adding :mime_type and :content_type to no avail.
Any help would be a appreciated.
Thanks!
This is what I tried and worked for me
attachments.each do |file|
attachment :content_type => MIME::Types.type_for(file.path).first.content_type, :body => File.read(file.path)
end
Is the file readable? Can you debug the issue by placing something like this?
logger.debug "File: #{file.full_path.inspect} : #{File.read(file.full_path).inspect[0..100]}"
Is there anything in your development.log?
Well, someone from the rails team answered my question. The problem lies with adding body content (#body) other than the attachment inside the method. If you're going to attach files you have to use a view template.

Resources