This is SaaS ("Rotten Potatoes") training question that has been discussed many times last year but I don't seem to find answer to this.
I have a form with checkboxes for ratings that generate hash named ratings. Then I uses params[:ratings] to pass latest checkbox selections to different pages. My code works correctly when user submits the form. But if they wander around without clicking the submit button then the latest values are lost.
I think that the latest values needs to saved whenever user checks/unchecks a checkbox, but don't know how.
I need to do this using haml and ruby, no javascript etc.
In you're movies controller you have the instance variable #selected_ratings where you save all the current ratings.
if params[:ratings] != session[:ratings] and #selected_ratings != {}
session[:ratings] = #selected_ratings
redirect_to :sort => sort, :ratings => #selected_ratings and return
end
#movies = Movie.find_all_by_rating(#selected_ratings.keys, ordering)
And in the movies index, in the form_tag you have
= check_box_tag "ratings[#{rating}]", 1, #selected_ratings.include?(rating)
For the sake of completeness.
Requirement was that if the user closes the web page and comes back later then the previous selections should be available. So I did it with cookies and passed the test case.
Related
So I'm trying to re-create GitHub version control for let's say posts. I've found a way to re-create an original post using duplicate AND another method to create a new post based on the original. Cool.
My issue is being able to display both the original and the new on the same page.
What I've attempted thus far is to just rely on the show method with having:
def show
#post = Post.find(params[:id])
end
Then in the view have in the form a checkbox to allow a user to select multiple posts, click a submit, and a new page renders displaying both side by side. Preferably showing the differences between the two but that's a wish list as I deal with this first.
Actually could I just simply do?:
def other_show
#post = Post.where(params[:id])
end
I also added in status as a boolean to help on the view for marking the checkbox. Would I then need to put something in the other_show method about the status?
If you want to "recreate" some sort of version control I suggest you use something like the audited. Instead of building your own. From your example and comments it seems you don't have a clear relation between all related (versions of) posts.
Using this gem, each change to the Post content (for example, if configured properly) would be stored as an audit.
Showing the differences is a different problem. That's usually called a diff and you can find gems that do it for you, for example: diffy
To show 2 different entities on one page you need to give posts_controller both ids.
Declare your show method like this:
def show
#original = Post.find(params[:id])
#compared = Post.find(params[:compared_id])
end
Correct route to this method will look like this:
/posts/:id?compared_id=:another_id
# Example: /posts/1?compared_id=2
To construct such a link in your view, you need to declare link_to method like this:
<%= link_to '1 <> 2', post_path(#post, compared_id: '2') %>
If you want to have a page where user can check 2 checkboxes for certain posts, you'll need to construct such href via Javascript.
But in fact I wouldn't suggest you to modify show method for such a task. It is better to use show method only for showing one entity from database. You can create another method, e.g. compare and pass both parameters there.
def compare
#original = Post.find(params[:original_id])
#compared = Post.find(params[:compared_id])
end
In routes.rb
resources :posts do
get 'compare', on: :collection
end
It will give you helper compare_posts_path, which will lead to /posts/compare and you'll need to pass original_id and compared_id to it, like this:
<%= link_to 'Compare', compare_posts_path(original_id: 'some_id', compared_id: 'some_another_id') %>
It will result to
/posts/compare?original_id=some_id&compared_id=some_another_id
I am a new rails developer and I have a rails app where I allow users to make a post while allowing them an option to check a checkbox. I want to be able to manually review all posts that are checked by users during their posting process. Right now everything is getting posted successfully but I want this review process in place for all checkmarked posts. What is the simplest and easiest way to put this review in place?
Here's what the post controller is right now
def create
#post = current_user.posts.build(params[:post])
if #post.save
flash[:success] = "Shared!"
redirect_to root_path
else
#feed_items = []
render 'static_pages/home'
end
end
For this, you better keep data-type of "reviewed" field as "boolean" (in migration files).
For putting up check box in your view, check:
http://guides.rubyonrails.org/form_helpers.html#helpers-for-generating-form-elements
Also, note that IF YOU WANT to validate the presence of boolean field (where the real values are true and false), you can't use:
validate :field_name, :presence => true
this is due to the way Object#blank? handles boolean values. false.blank? # => true
In this case, you can use:
validates :field_name, :allow_nil => true, :inclusion => {:in => [true, false]}
You can omit ":allow_nil => true", from above validation statement if you are assigning false as default value to newly created posts (and that you would require to do before validations get triggered).
I'm not talking in perspective of RoR, but in general implementation
In the database, add a field called 'Reviewed'. It holds a 'Y' or 'N'. default should be 'Y'.
Now, while saving or Updating the post make the check box flag a Y or N into this field and
in the Model, Only query for posts with 'Reviewed' = 'Y'.
This way, if the user does not check the box, the default value is 'Y' and the posts shows up, but if the user checks the box, the value shall be 'N' and you develop a review interface (i hope you already did) where after review, you mark it to 'Y'.
This is as simple as it can get. If you need to add more information on who review it, when it is reviewed etc, you can add more DB fields to store that.
Update
I work on ColdFusion technology and we have CFWheels framework which is inspired by RoR.
Based on the experience, I suggest you to use the Form helpers.
Try this code
<%= check_box_tag(:post_reviewed) %>
<%= label_tag(:post_reviewed, "Review this post") %>
And for more details, read check box tag in ruby on rails and check box form helper
I have followed railscast #198 Edit Multiple Individually and it works 100% for editing multiple records from a single form.
However, I would like to also create new records from the same form if the record. i.e. in the controller assess the hash of params from the form, update those records that exist and create the records that don't exist.
Also, if any validation errors occur they should be caught and passed back.
This in the controller works and will update correctly if the fields for the new record aren't present
#costs = IngredientCost.update(params[:ingredient_costs].keys, params[:ingredient_costs].values).reject { |item| item.errors.empty? }
For the fields for the new records I am currently creating an artibrary large unique number as the record id (I'm not sure if this is right to do) and then the message comes back that it cannot be saved because the id doesn't exist, which is to be expected as I it doesn't exist.
I've tried the following two snippets as a stab in the dark but not really sure which way I should be going..
#costs = IngredientCost.find_or_initialize_by_id(:id => params[:ingredient_costs].keys).update(params[:ingredient_costs].keys, params[:ingredient_costs].values).reject { |i| i.errors.empty? }
and
params[:ingredient_costs].each do |ingredient_cost|
#cost = IngredientCost.find_or_initialize_by_ingredient_id_and_user_id(:ingredient_id => ingredient_cost[1]["ingredient_id"], :user_id => current_user.id)
#cost = IngredientCost.update(:ingredient_id => params[:ingredient_costs][ingredient_cost[0]]["ingredient_id"], :quantity => params[:ingredient_costs][ingredient_cost[0]]["quantity"], :price_per_unit => params[:ingredient_costs][ingredient_cost[0]]["price_per_unit"], :weight_id => params[:ingredient_costs][ingredient_cost[0]]["weight_id"])
Neither seem to work.
I've seen this work before but for updating/creating nested attributes from one form. I don't really want to have to go that route with this.
I eventually resorted to saving the multiple records through a parent model which already had the correct associations.
I followed Railscast #196 Nested Model Forms which was fairly similar to above only saving to another model and placing accepts_nested_attributes_for in that model's *.rb.
Remember to move the routes.
Move the controller code to the receiving action of the parent model.
My form in the viewer now looks like this (in haml format):
= form_for #user, :remote => true do |f|
= f.fields_for :ingredient_costs do |builder|
// fields inserted here
It took me a couple hours to realise I had to use builder.object... to get to the child that I actually am interested. The .object class wasn't obvious to me.
Anyway, hope this was useful to someone. I think SybariteManoj's answer looks like a good deal, but I couldn't get it to work.
You can try following snippet:
#costs = []
params[:ingredient_costs].each do |ingredient_cost|
if ingredient_cost[:id].blank?
cost = IngredientCost.create(ingredient_cost)
#costs << cost
else
cost = IngredientCost.find(ingredient_cost[:id])
cost.update_attributes(ingredient_cost)
#costs << cost
end
end
P.S. I haven't tested it yet. But for the re-rendering the edit page with the errors, the #costs variable has the data with errors if any.
What I am trying to do is build a form in which the user fills some of the fields for a new Publication, and takes you to the New Publication action, with those fields already filled in, so the user fills the rest.
I got the controller part covered, but I cant find how to use form_for for this, as its not exactly associated to the model (only some of the necessary fields are in the first form).
you could do
form_tag new_publication_path()
Not necessarily the best way to do this, but you can hide some of the fields in the form depending on whether the model id is valid. For example (in haml):
- if #model.id #only shows up if the model has been saved.
= f.text_field :field_name, ...
This way you can use the usual new, and then when the model has been saved, just redirect to the 'edit' action and the rest of the fields show up.
How do I create some simple ajax rating like there is on this page http://watir.com/documentation/ ? Every visitor should be able to rate, I dont need to set permissions. I want to store the ratings in a column. So the user can sort by ratings.
Please make an detailled example. I am not a javascript expert.
I have found an example to create ratings from scratch. But it authorizes a user.
Can someone show me a guidance to create ratings without a Rater (user)? It should not only store the values but also count the votes.
http://eighty-b.tumblr.com/post/1569674815/creating-an-ajaxified-star-rating-system-in-rails-3
What I did recently to add a simple rating mechanism to an existing project was the following:
I added two fields to an existing table (which contained the items to be rated). Those were:
rating_score => The current score
ratings => The number of ratings which led to the score
For example, if five users would've voted "5" for the current item, rating_score would be 25, and ratings would be 5. The current rating would be computed as rating_score / ratings.
Then I added a new method to the controller of the items to be rated, called "rate", which looked something like:
def rate
#item = Item.find(params[:id])
#container = "item"+#item.id.to_s
#item.rating_score += params[:rating].to_i
#item.ratings += 1
#item.save
respond_to do |format|
format.js
end
end
My view for that method, called rate.js.erb, would look something like
$('#<%= #container %>').html('<%= escape_javascript(render(partial: 'rating', locals: { item: #item })) %>');
This code works only if you've got jQuery installed, but it should be easily translatable to Prototype or whatever JS framework you may be using.
And the partial for the rating, called _rating.html.erb, was something like:
<%= form_tag url_for(controller: 'items', action: 'rate', id: item.id), remote: true %>
<%= rating_stars(item.rating_score, item.ratings) %>
<%= item.ratings %> Votes
</form>
In this partial, the rating_stars() helper method generated some kind of star-like representation for the rating, but you can do that however you like.
By setting "remote: true" in the form_tag helper, your Rails installation should automatically transmit the request via the installed Javascript framework. This magic is part of the whole unobtrusive javascript thing going on in Rails lately, which is actually pretty cool.
Hope this gives you an idea of how to realize a very simple rating system with no IP lock feature whatsoever in Rails.
Looks like the Watir documentation rating system is set up through polldaddy.
For this particular case, it appears they include the polldaddy javascript which populates the rating div container with their star rating widget. Looks like there's a corresponding javascript object which you can inspect:
console.log( PDRTJS_101132_page_2.avg_rating ); //=> 4
If you had numerous rating widgets like these on a page, and you were able to make a collection of the javascript objects paired with their divs, presumably you could sort them based on that average rating property.