I am learning Ruby and Rails.
I have a Ruby on Rails project that tracks jobs a server is running. Right now, when I manually create a new job, it announces:
flash[:notice] = "Created job job number #{update.id}."
I would like to turn the #{update.id} into a link to the job on the job list.
The URL for going to the job is jobs/list?job=1234 where 1234 is the update.id that is displayed in the flash notice.
Is it possible to put a link into a flash[:notice] statement? Or do I need to re-work how this message is being displayed in order to turn it into a link?
Don't forget to add .html_safe at the end of the notice, if you're using Rails3.
So it would say flash[:notice] = "Your message".html_safe
The #template instance variable is no longer available in Rails 3.
Instead you can use this in your controller:
flash[:notice] = "Successfully created #{view_context.link_to('product', #product)}.".html_safe
Hope this helps :)
I may be missing something obvious, but you should just be able to do
flash[:notice] = %Q[Created job number #{update.id}]
and then just make sure you're not escaping the content of the flash when you display it in your view.
As nas commented, link_to is not available from your controller unless you include the appropriate helper module, but url_for is. Therefore I'd do pretty much what Emily said except use url_for instead of hardcoding a URL.
e.g. if a job were defined as a resource in your routes:
link = "#{update.id}"
flash[:notice] = "Created job number #{link}"
The selected answer didn't work for me. But the answer from this post worked. I'm using Rails 4.2.4 by the way. With guidance from the answer I linked, here's how I did it:
View
<% flash.each do |name, msg| %>
<div class="alert alert-<%= name %>">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<div id="flash_<%= name %>"><%= sanitize(msg) %></div>
</div>
<% end %>
Controller
flash[:success] = "Blah blah. #{view_context.link_to('Click this link', '/url/here')}"
The magic is the sanitize method.
I didn't need to use .html_safe as well.
Building on Dorian's answer, here's an internationalized flash with a link in it:
flash[:notice] = t('success', go: view_context.link_to(t('product'), #product)).html_safe
Where your translation (e.g. a YAML file) might contain:
en:
success: "Successfully created a %{go}"
product: "product"
it:
success: "%{go} creato con successo"
product: "Prodotto"
You can use an alias in your controller to the link_to function, or the RailsCast recipe:
"Created job job number #{#template.link_to update.id,
:controller => 'jobs', :action => 'list', :job => update.id}."
http://railscasts.com/episodes/132-helpers-outside-views
You can always use the Rails link_to helper:
flash[:notice] = "Created job job number #{link_to update.id, :controller => 'jobs', :action => 'list', :job => update.id}."
Related
Actually I need a big help, I'm using rails 5.1.4, I get stuck when rendering a partial with ActionCable and background Jobs. In my partial, I have a condition on current_user to check if current_user is the message owner and get his username with green color to make somes differents, so far display an update and delete button for each message he's the owner in the room conversations. But, if I refresh the page or remove current_user in the partial before rendering it works. However, I want that condition happens. Or, looking for a best way if there is one. THANKS IN ADVANCE.
Here is the error displayed in my terminal:
ERROR: ActionView::Template::Error: Devise could not find the warden::Proxy instance on your request environment.
Those are my files content.
The partial: _conversation.html.erb
<div id="message">
<% if conversation.user == current_user %>
<span style="text-align: center; color: green"><%= conversation.user.username %>
</span>
<% else %>
<span style="text-align: center; color: magenta"><%=
conversation.user.username %></span>
<% end %>
<p style="color: black"><%= conversation.body %></p>
</div>
Message_controller.rb
def create
conversation = #room.conversations.new(conversation_params)
conversation.user = current_user
conversation.save
MessageRelayJob.perform_later(conversation)
End
Room/show.html
<div id="conversations" data-room-id="<%= #room.id %>">
<%= render #room.conversations %>
</div>
MY JOB CLASS
class MessageRelayJob < ApplicationJob
queue_as :default
def perform(conversation)
ActionCable.server.broadcast "room_tchats_#{conversation.room.id}_channel",
conversation: render_conversation(conversation)
end
private
def render_conversation(conversation)
ConversationsController.render partial: 'conversations/conversation', locals: {conversation: conversation}
end
end
It can be happening when you try to get Devise current_user in some part of code being managed by action cable. like a background job to render comment or something else. you can resolve it by using something like following in your controller, since you cant access warden at a model or job level(according to my limited knowledge): (I call a job right after creation of my comment in CommentsController create action, which calls a private method to render a comment partial containing edit and delete button, for which current_user was required)
def create
#product = Product.find(comment_params[:product_id])
#comment = #product.comments.build(comment_params)
#comment.save!
gon.comment_id = #comment.id
gon.comment_user_id = #comment.user_id
ActionCable.server.broadcast "chat", comment: render_comment
render :create, layout: false
end
def render_comment
CommentsController.renderer.instance_variable_set(:#env, {"HTTP_HOST"=>"localhost:3000",
"HTTPS"=>"off",
"REQUEST_METHOD"=>"GET",
"SCRIPT_NAME"=>"",
"warden" => warden})
CommentsController.render(
partial: 'comments/comment_detail',
locals: {
product: #product,
comment: #comment
}
)
end
this will help you resolve warden issue, if you have used devise's current_user in that partial, it will give you the commentor user (as it should since that user initiated the rendering of partial). Now to solve this, if you have a front end framework you might need to fetch the current user from cookies in order to restrict some actions like edit/delete. but if you are working in pure rails the solution I came across is that you have to make a hidden field in the dom having current users id, and you will fetch that id for comparison in a script. you might need to access rails variables in javascript, for that you can use GON gem. I know this answer might contain much more than asked but I've searched alot and no where I found a satisfactory solution to this problem, feel free to discuss.
So I'm trying to create a new "transaction" each time I click the button "Purchase", but doesn't seem to work. I get the error "undefined method `[]' for nil:NilClass".
<% #comics.each do |comic|%>
<ul>
<li><%= comic.title %> </li>
<li><%= comic.author %> </li>
<li><%= comic.year %> </li>
<li><%= comic.publisher %> </li>
<% if user_signed_in? %>
<%= button_to 'Purchase', {:controller => "transactions", :action => "create", :seller_id => comic.user_id, :buyer_id=> current_user.id, :comic_id => comic.id} , {:method=>:post} %>
<% end %>
</ul>
This is what you can find in the transactions controller:
def create
#my_transaction = Transaction.new(
buyer_id: params[:transaction][:buyer_id],
seller_id: params[:transaction][:seller_id],
comic_id: params[:transaction][:comic_id]
)
#my_transaction.save
redirect_to "/transactions/"
end
Do you have any idea why this might be happening?
Thanks!
There are a couple of ways you can debug this:
Look in the console logs to see what is being posted in the params hash.
add a puts statement at the top of the create statement to view what is in the params variable e.g.
controller
def create
puts params.inspect
end
I suspect you'll find that the params hash does not have a transaction key and the create method should be
def create
#my_transaction = Transaction.new(
buyer_id: params[:buyer_id],
seller_id: params[:seller_id],
comic_id: params[:comic_id]
)
end
The params[:transaction] is nil, you can see the sent parameters in the log (tail -f log/development.log if the server doesn't log). In your case you access the required data like params[:comic_id]
A few tips:
Never trust the input coming from the client:
:buyer_id=> current_user.id here an attacker could send any ID since the button_to helper will create a html form which is easily accessible using the devtool. Instead check it on the server side. Same goes for the seller_id, you can just fetch the related comic comic = Comic.find params[:comic_id].
You might want to consider an another API approach like POST /comics/1/buy this is a bit more restfull, and you could use the built in path helpers for that url like buy_comic_path(comic)
I have ideas controller and static_pages controller. The latter has home action which displays all ideas and which i also use as root path.
I want the user be able to Edit the displayed ideas. So far i have this:
<% if #ideas.empty? %>
<p>Share your ideas! See what people think about it.</p>
<% else %>
<% #ideas.each do |idea| %>
<div class="panel panel-default">
<div class="panel-heading"><%= idea.name %></div>
<div class="panel-body"><%= idea.description %> <br>
<%= link_to 'Edit', edit_idea_path(idea.id) %>
</div>
</div>
<% end %>
<% end %>
I had an issue with an empty idea id which i solved by adding idea.id inside edit_idea_path
Now my question is, is that the proper, Rails way of doing it? In what other way can i fetch the idea object from this index page and use it in my ideas controller instead of static_pages controller?
I tried playing around with routing, but I have very vague understanding of it despite reading the guides and others code. I'd appreciate any insight about this matter.
First you need to understand that the requirement of your project defines what you should do in the code, whithout of concerning about the proper way to do something. You just need to follow the rails conventions.
http://guides.rubyonrails.org/active_record_basics.html#convention-over-configuration-in-active-record
Now, back to your question. You just need to create an action (that will handle a view) in your ideas_controller that will manage the edition of the data sended by de static_pages_controller, i will call it (just for example) edit_static_ideas and receive the data with params:
In your ideas_controller : app/controllers/ideas_controller.rb
def edit_static_ideas
#idea = Idea.find(params[:id])
end
Then you need to create the view in your views->ideas folder. An name it, just to continue my example i'll name it edit_static_idea.html.erb. And set the load of the data you get in #idea as a form or a form_for. Then you can submit that edited data and upload it into other action.
Then you have to configure your routes file and add
config/routes.rb
get 'edit_static_idea/:id', to: 'ideas#edit_static_idea', as: 'edit_ideas'
After that, if you run "rake routes" in your console (inside your rails project), you should see your new route (yay!)
Now you have to take the path in your route and use it in you static_pages_controller's view to redirect it to the edit_idea's view handle it by ideas_controller. And be sure that you also send the id of the selected item.
app/views/static_pages/home.html.erb:
<%= link_to 'Edit Idea', insert_your_edit_idea_obtainedinrakeroutes_path(id: idea.id) %>
At last, you only need to configure the form in your edit_static_idea.html.erb and assign it an upload/save route and redirect it to the view that you want.
for example:
In your routes file: config/routes.rb
patch 'save_edited_idea', to: 'ideas#save_edited_idea', as: 'save_edited_idea'
In your ideas_controller: app/controllers/ideas_controller.rb
def save_edited_idea
#idea = Idea.find(params[:id])
respond_to do |format|
if #idea.update(idea_params)
format.html { redirect_to the_view_that_you_want_path(id: #idea.id), notice: 'Data saved without problems.' }
else
flash.now[:alert] = "error"
format.html { render :offer }
end
end
end
I didn't wanted to be so detailed, because i wanted to help you to understand what you have to do. I hope it helps :P
I am new using Ruby On Rails so this question may seem stupid. I've been searching a lot tutorial and sort of understand what I could do, but what the code looks like exactly? how i should implement this and where to put them still confuse me.
I have a database called note which has two attributes, :note whose type is text and a foreign key called user_name whose type is string. In the main.html.erb, I have my main page and also a note pad whose is a text area. here's part of main
<div class="four columns" id="note">
<textarea id="area" style="width:250px; height:300px;" placeholder="Your notes starts here"><%= #note %></textarea>
<div id="clear" class="primary btn pretty">Clear</div>
<div class="secondary btn pretty"><%= link_to 'Save', controller: 'main', action: 'update_note', :remote => true, :method => :put %></div>
</div>
By the way, I'm using Gumby. so My button is called "Save". I want the user to input their note in the txtfiled and when they click the "save" button, it will update the note database in the row according to the user_name.
So my question is, should I write a action on main_controller or notes_controller. How should I do it. Sample could would be much helpful since I tried different way and it is really frustrating.
I tried putting the code in the main_controller like this:
def update_note
#note = Note.find_by(user_name: session[:user_name])
respond_to do |format|
if#note.update_attributes(params[:note])
format.html { redirect_to #note, :notice => 'Note was successfully updated.' }
format.js
else
format.html { render :action => "edit" }
format.js
end
end
end
as well as tried to put code in notes_controller. but I get "No route match"
I totally mess up. And it'd due tomorrow! thanks for any help. It's so nice to refers me some link of tutorial but the anything related to my code would be more helpful!
Thanks!
You would have to use a form for this or you can also do it by using Jquery Ajax.
First add a gem 'jquery-rails' to Gemfile and then do bundle install.
in Gemfile:
gem 'jquery-rails'
Next require both jquery and jquery_ujs into your /app/assets/javascripts/application.js manifest like this:
//= require jquery
//= require jquery-ujs
in /views/layouts/application.html.erb:
<%=javascript_include_tag "application.js"%>
#I guess it will be already there
in /views/main/home.html.erb
<%= form_tag({:controller=>'main',:action=>'update_note'},:method=>:post,:id=>"update_note",:name=>'note_form',:remote=>true) do %>
<div class="four columns" id="note">
<textarea id="area" name="note" style="width:250px; height:300px;" placeholder="Your notes starts here"><%= #note %></textarea>
<div id="clear" class="primary btn pretty">Clear</div>
<div class="secondary btn pretty"><%= submit_tag 'Save' %></div>
</div>
<%end%>
<div id="updated">
</div>
in main_controller.rb
def update_note
#note = Note.find_by(user_name: session[:user_name])
if #note.update_attributes(params[:note])
#updated = "true"
format.js
else
#updated = "false"
format.js #this will load update_note.js.erb
end
end
Create a file update_note.js.erb under ../views/main/
Now in app/views/main/update_note.js.erb:
<%if #updated == "true"%>
$('#updated').html("Your post has been successfully updated").show();
<%elsif #updated == "false"%>
$('#updated').html("Your post could not be updated").show();
<%end%>
And at last add this in /config/routes.rb:
#in Rails 3
#match "main/update_note" => "main#update_note"
#in Rails 4
match 'main/update_note' => 'main#update_note', :via => [:post]
Open this home page where you have the update_note textbox, open up console in Chrome/ Firefox. Now check under Net tab in the console (in Firefox) or Network tab (in Chrome) and check for the request being made when you click on Save button. Let me know if you find any difficulty.
Hey all,(im a beginner in rails)
i've created a controller that look like that:
class HomeController < ApplicationController
def homepage
end
def showmsg
#postword = params[:p]
end
end
the showmsg view looks like that:
<%= #postword %>
and my homepage view looks like that:
<%= form_tag( {:controller => 'home', :action => 'showmsg'}, :method => "post") do %>
<%= text_field_tag(:p,#postword) %>
<%= submit_tag("post") %>
<% end %>
now i have a form that i can write something in it and it will show on the showmsg view.
i created a model with the param :posts with a :description "text" field too.
MY QUESTION is how do i implement the model in the code so any thing i write will be in a list with the things i wrote before, because now (obviously) anything if i write something its deleting the one i wrote before.
thank you all!
I would argue that you're approach is not very rail's like... so if you're learning rails... you're learning it wrong.
Make a Model. Call it "Message":
rails generate model Message content:string
remember to migrate (hopefully you have your databases setup properly):
rake db:migrate
Then in your controller, when you post, you can create message like this:
def create #instead of showmsg... 'create' is the standard name for this
Message.create(params[:message])
#messages = Message.all
end
This will create the message in the database, and then it will get all the messages out of the database and put them into #messages.
You need to edit your form so that it uses form_for. You need to pass it #message, which is an instance of Message.new that your first controller action created. You should call this new
In your create.erb.html file, you show all the messages like this:
<ul>
<% #messages.each do |message| %>
<li><%= message.content %></li>
<% end %>
</ul>
I actually wouldn't recommend showing all the messages in the create action - it should really happen in the index action and you should redirect... but we need to keep this simple. Just google this or watch some of Ryan's screencasts and you'll get it.
And you're done. This is the "Rails Way" to do things. It's best to learn it the way they want you to learn it.
I would also commend that you format your code properly by indenting, and start naming your methods to be real english. For example, showmsg is bad and show_message is a lot better.
If all of this is totally confusing, then just create a new project, and then type:
rails generate scaffold message content:string
It will basically build the application you want and a lot more. You can just read the code and see how they did it.
Hope it helps.
Your approach is not really rails like so some tweaks and fixes are needed. Suggestions: check rails approach to REST. The following code will work it is a little more rails like, but still not all the way there.
Generate a model
rails generate model Message postword:string
this will generate the model and create the migration necessary to create the table in the database.
Create the table
rake db:migrate
Define a post action
It will save the postword in the database. In your controller:
def create
#message = Message.create!(params[:message])
if #message.save
redirect_to "/home/showmsg"
else
render :action => "/home/homepage"
end
end
Create and instance of Message to use in your form
def homepage
#message = Message.new
end
Fix your form tag
<%= form_for #message, :url => "/home/create" do |f| %>
<%= f.label :postword %>
<%= f.text_field :postword %>
<%= f.submit "Create" %>
<% end %>
Now let's show the words in the showmsg page
In the controller select the postwords from the database:
def showmsg
#postwords = Message.all
end
Showing them: /showmsg.html.erb
<H1>postwords list</H1>
<ul>
<% #postwords.each do |p| %>
<li><%= p.postword %></li>
<% end %>
</ul>
Your routes.rb file will have this routes:
get "home/homepage"
get "home/showmsg"
post "home/create"
Define an attribute :new_text in a way similar to this:
class TheModel
# Virtual writer - everything assigned to this attribute
# will be added to self.text
#
def new_text=(v)
self.text += v.to_s
end
def new_text
"" # This is write-only attribute
end
end
Now, use the field 'new_text' in your form.
Of course, this is a very simple example. You should decide whether you want to add the content on every call to :new_text=, maybe some validation would help, the read accessor may need some care, and so on.
For some good guides which may help you start, see the site http://guides.rubyonrails.org/